QC Results Are Not Patient Results: Separating Them in Middleware

L
LIS Bridge
Sep 24, 2026
QC Results Are Not Patient Results: Separating Them in Middleware

Laboratory quality control middleware has to tell a control run from a patient sample before routing. Here is how message classification keeps QC out of the patient record.

QC Results Are Not Patient Results: Separating Them in Middleware

Your hematology analyzer ran three things this morning. A level-1 control at 07:10. A calibration verification at 07:25. And, from 07:40 onward, patient specimens. All three left the analyzer on the same cable, in the same message format, through the same port, to the same piece of software.

Whether those three things stay separate after that point is a question about your middleware, not about your analyzer. The analyzer usually says what it is sending. Most middleware does not stop to listen.

Laboratory quality control middleware — middleware that classifies a message before it routes it — is the difference between a control value living in your QC record and a control value living in a patient chart. This post covers what analyzers actually say, why single-pipeline designs get it wrong, and what the current standards work expects.

The Four Things an Analyzer Actually Says

It is tempting to think of an instrument link as a result feed. It is not. Across the dialects LISBridge parses, an analyzer connection carries at least four distinct kinds of traffic:

  • Patient results. A measurement on a human specimen, destined for a chart.
  • Quality control results. A measurement on a control material with a known expected range, destined for your QC log and your Levey-Jennings charts.
  • Calibration data. Values produced while the instrument establishes or verifies its own measurement scale, destined for instrument records.
  • Queries. The analyzer asking a question — most often "what tests should I run on this specimen?" — which is not a result at all and needs an answer, not storage.

The dialects carry this distinction in different places. In HL7 v2.3.1, the HTSH-2000 biochemistry analyzer flags transmission kind in MSH-16: 0 for a patient sample, 1 for calibration, 2 for QC. In ASTM E1394, the specimen type and control identifiers in the Patient and Order records carry the signal. On the Tosoh HLC-723GX, which speaks neither standard, the GX-format record distinguishes a specimen from a calibrator structurally, and carries an explicit CALIB type field.

Every one of those is the analyzer telling you, unprompted, that this reading is not a patient reading. The information is present. The question is whether anything downstream acts on it.

Why a Single Pipeline Lets a Control Land in a Patient Record

Most integration failures here are not dramatic. They look like this.

Middleware built as a single pipeline treats every inbound message the same way: parse it, pull out the sample identifier and the analyte values, and forward. Classification, if it happens at all, happens as a filter near the end — usually a rule someone wrote by hand, matching control lot numbers or specimen ID patterns.

That design fails in three predictable ways:

The pattern rule goes stale. A QC filter keyed to sample IDs beginning with "QC" works until the day a technologist types the control ID slightly differently, or the lab changes control vendors and the new lot numbering does not match. The rule silently stops matching. Nothing errors. The controls simply start flowing into the patient stream.

Calibration is forgotten entirely. Labs that build a QC filter often never build a calibration filter, because calibration traffic is rarer and nobody thought about it. Then a calibration verification run produces values that look like plausible patient results with an unfamiliar specimen ID, and they sit in the system as orphans — or worse, match a real specimen by coincidence.

Retrospective cleanup is expensive. Once a control value has been posted to a chart, removing it is a documented correction with a paper trail, not a database delete. The cost of the mistake is not the bad value — it is the amendment process that follows it.

The failure mode that matters most is the quiet one. A control result in a patient record does not throw an exception. It looks exactly like a result. It is found weeks later, during a chart review, by someone who was not looking for it.

Classifying Before Routing: How LISBridge Handles It

LISBridge moves classification to the earliest possible point — inside the parse envelope, before any routing decision is made.

When a message arrives from an analyzer, the parser does not just extract values. It labels the message as result, qc, calibration, or query, using whatever the analyzer's own dialect provides for that purpose. That label travels with the message as a first-class property, not as an inference made later by a rule.

Routing then follows the label:

  • Results continue into the patient pipeline and on to your LIS or HIS, exactly as before.
  • QC and calibration traffic is diverted out of the patient pipeline entirely. It never reaches the LIS delivery stage, so there is no mechanism by which it can be posted to a chart.
  • Queries are answered rather than stored — the analyzer asking for a worklist gets a worklist, which is a conversation, not a record.

Because the classification lives in the message record itself, the message class is also a stored column. That means the separation is not just a routing behaviour you have to trust — it is something you can look at. The Quality Control page shows QC traffic on its own, and the request history keeps a record of every query the analyzer raised and every answer that went back. You can see what arrived, what class it was assigned, and where it went.

This sits alongside the raw-frame retention described in our post on the lab result audit trail: the original protocol data is stored beside every parsed message, so a classification decision can always be checked against the bytes that produced it. For the parsing layer underneath all of this, see data parsing; for the live view of what each link is doing, see real-time monitoring.

What the Standards Work Says About This

This is not a design preference. The direction of standards work in laboratory automation treats patient and non-patient work as structurally different, not as the same thing with a flag on it.

The IHE Laboratory Analytical Workflow (LAW) profile models the exchange between an analyzer and its manager as a sequence of work-order steps, and distinguishes the work-order step for a patient specimen from the handling of QC material. The profile's whole premise is that "the analyzer sent a number" is not enough information — the number belongs to a specific, typed piece of work.

The CLSI AUTO16 work on laboratory automation and analyzer interfacing continues in the same direction: specifying the interaction rather than just the payload, so that the receiving system knows what kind of transaction it is participating in.

The practical read for a lab: standards bodies are converging on the position that classification belongs in the interface, not in a downstream cleanup rule. Middleware that classifies at parse time is aligned with where this is going. Middleware that pattern-matches control IDs is not.

What Accreditation Reviewers Actually Ask For

Inspectors do not generally ask to see your message classification logic. They ask questions that your classification logic determines the answer to.

"Show me your QC record for this analyzer for this month." If QC is diverted to its own store, this is one screen. If QC is mixed into the general result flow and filtered by rule, this is a query someone has to construct, and its completeness depends on whether the rule was matching correctly the whole time.

"How do you ensure control results are not reported as patient results?" The strong answer is architectural: QC never enters the patient delivery path, because it is classified before routing. The weak answer is procedural: staff check.

"Show me the original data for this result." Answerable when the raw protocol frame is retained alongside the parsed record, as described above.

"What happened between the analyzer and the LIS at this timestamp?" Answerable when query traffic is recorded as history rather than discarded.

The common thread is that every one of those questions is easier to answer when the system knew what kind of message it was handling at the moment it handled it.

FAQ

Does every analyzer flag its QC runs?

Most do, in some form — but the mechanism varies widely, which is why classification has to be dialect-aware rather than generic. HL7 analyzers commonly use a transmission-kind field in the message header. ASTM analyzers signal through specimen and control identifiers in the Patient and Order records. Non-standard analyzers like the Tosoh HLC-723GX carry an explicit calibrator distinction in their own record format. Where an analyzer genuinely provides no signal, that is worth knowing explicitly before you connect it, rather than discovering it later.

Can I still send QC results to my LIS if I want to?

Yes. The point of classification is that the routing becomes a decision you make rather than an accident that happens. Labs whose LIS has a proper QC module often do want that traffic delivered — to the QC module, as QC, not into the patient result stream.

What happens to calibration data?

It is classified and diverted out of the patient pipeline the same way QC is, and retained where it can be reviewed against the instrument record. Calibration is the category most often overlooked in hand-built filters, which is exactly why it is handled as a first-class class rather than as an afterthought.

Does this work on serial analyzers, or only networked ones?

Classification happens at the parse layer, above the transport layer, so it applies identically across RS-232 serial, TCP/IP, and FTP/FTPS/SFTP file transport. A control result arriving over a serial cable is classified the same way as one arriving over the network.

Do I need to write rules to configure this?

No. The classification comes from the analyzer's own dialect and is applied by the parser. There is no rule to maintain, and therefore no rule to go stale when your control lot numbering changes.

The Short Version

A control, a calibrator and a patient specimen all leave the analyzer on the same wire. Every dialect gives you the means to tell them apart. Middleware that reads that signal at parse time, before routing, makes the patient pipeline structurally incapable of receiving a control value — which is a much stronger guarantee than a filter that has to keep working.

If you want to see what your own analyzers are already telling you, connect one and look at the message classes.

Start your free trial — no credit card required. lisbridge.com/pricing

Comments (0)

Leave a comment

No comments yet. Be the first to leave one!