Verial
guideshl7v2adttesting

HL7v2 ADT Testing Guide: Simulated Hospital Feeds [2026]

A practical guide to testing healthcare AI agents against HL7v2 ADT feeds: MSH parsing, MLLP transport, test scenarios, and realistic admission events.

S
Stan Liu · Co-founder, Verial
·7 min read
Share

TL;DR

  • Testing AI agents against HL7v2 ADT feeds needs a simulated MLLP listener, realistic message generators, vendor-specific variations, and scenario playback for admit/transfer/discharge sequences.
  • Over 95% of US hospitals still use HL7v2 for ADT messaging per HL7 International and KLAS research, even as FHIR adoption grows.
  • A typical health system generates 200,000+ HL7v2 messages per day across ADT, ORU, and ORM feeds (HIMSS interoperability research).
  • If your agent reacts to real-time hospital events, it must parse ADT, ACK cleanly over MLLP, and handle out-of-order messages. For the strategic context, see why HL7v2 is not dead.

Why ADT testing matters

ADT (Admit, Discharge, Transfer) messages are the heartbeat of hospital operations. Every admission, transfer, and discharge generates an HL7v2 message that flows through the integration engine to downstream systems. If your agent needs real-time awareness of patient movement, census, or admission events, it must consume and process these reliably.

Testing against live hospital feeds is impractical. You cannot connect a dev agent to a production interface engine, generate test admissions in a live system, or predict real message volume and timing. This is part of a broader challenge: healthcare AI agents need sandbox environments that replicate real behavior.

What you can do is build a simulated feed that produces realistic messages at realistic rates with realistic variations. This guide covers structure, transport, parsing, and test scenarios.

"HL7v2 is the dial tone of hospital interoperability. FHIR sits on top of it, not instead of it."

Grahame Grieve, HL7 FHIR Product Director, HL7 International

ADT message types that matter

The ADT family has 60+ trigger events. In practice your agent sees a smaller subset:

  • A01 Admit. Inpatient admission. Full demographics, insurance, admitting diagnosis, bed.
  • A02 Transfer. Patient moved between units. PV1 updates with new location.
  • A03 Discharge. Patient leaves. Discharge disposition, final diagnoses, attending physician.
  • A04 Register. Outpatient or ED registration.
  • A08 Update. Demographics, insurance, or visit info changed. Fires frequently.
  • A11 Cancel Admit. A01 was in error. Reverse it.
  • A13 Cancel Discharge. A03 was premature. Patient is still in the facility.
  • A28 Add Person. Master patient index update.
  • A31 Update Person. Person-level demographics update without an active visit.

Message structure essentials

A typical A01 starts with MSH, then EVN, PID, PD1, NK1, PV1, PV2, IN1, DG1, GT1:

MSH|^~\&|EPICADM|MAIN_HOSP|AGENT_SYS|VERIAL|20260324143022||ADT^A01^ADT_A01|20260324143022001|P|2.5.1
EVN|A01|20260324143022|||JSMITH^SMITH^JANE^M^^MD
PID|1||E12345678^^^EPIC^MR~987654321^^^SSA^SS||JOHNSON^ROBERT^A^JR^^||19651204|M
PV1|1|I|4NORTH^4N12^A^MAIN_HOSP|||1234567^SMITH^JAMES^A^^^MD
IN1|1|BCBS001^BLUE CROSS|BCBS123|BLUE CROSS BLUE SHIELD OF IL
DG1|1||R06.02^Shortness of breath^ICD10||20260324|A

Key MSH fields: sending app/facility (MSH-3/4), receiving app/facility (MSH-5/6), timestamp (MSH-7), message type (MSH-9), control ID (MSH-10), processing ID (MSH-11, P for production), version (MSH-12).

Key PID fields: identifiers (PID-3, repeating), name (PID-5), DOB (PID-7), sex (PID-8), address (PID-11).

Key PV1 fields: patient class (PV1-2, I for inpatient), assigned location (PV1-3, unit^room^bed^facility), attending (PV1-7), admit timestamp (PV1-44).

Connecting via MLLP

HL7v2 is transmitted over MLLP, a thin TCP framing protocol. Each message is wrapped:

  • Start block: 0x0B
  • Message content
  • End block: 0x1C followed by 0x0D

A minimal listener:

import net from 'net';
const SB = '\x0b', EB = '\x1c', CR = '\x0d';
 
const server = net.createServer((socket) => {
  let buffer = '';
  socket.on('data', (data) => {
    buffer += data.toString();
    while (true) {
      const start = buffer.indexOf(SB);
      const end = buffer.indexOf(EB + CR);
      if (start === -1 || end === -1) break;
      const message = buffer.substring(start + 1, end);
      buffer = buffer.substring(end + 2);
      const ack = processMessage(message);
      socket.write(SB + ack + EB + CR);
    }
  });
});
server.listen(2575);

After receiving, send an ACK (MSA segment with AA, AR, or AE). If your agent does not ACK promptly, the sender retries, causing duplicate processing.

Parsing challenges

  • Field repetitions. PID-3 often repeats. Split on tilde and keep each value with its assigning authority.
  • Component separators. PV1-3 uses carets: 4NORTH^4N12^A^MAIN_HOSP. Empty components matter, do not collapse them.
  • Escape sequences. \F\ = pipe, \S\ = caret, \T\ = tilde, \R\ = backslash, \.br\ = line break. NTE and OBX segments are full of them.
  • Segment ordering. The spec defines order; reality does not always comply. Index segments by identifier, access by type.
  • Z-segments. Custom hospital and vendor segments (ZPD, ZIN, ZDG). Often contain the operationally relevant data.

Test scenarios

Basic patient journey

  1. A04: Patient registers in the ED
  2. A08: Insurance added
  3. A01: Admitted to inpatient from ED
  4. A02: Transferred to ICU
  5. A02: Transferred back to med-surg
  6. A03: Discharged home

Verify state tracking and current-location correctness at each step.

Burst and sustained volume

Hospitals can generate hundreds of messages per hour at shift changes. Test:

  • 50 A01 messages in 5 minutes
  • Interleaved messages for multiple patients
  • Sustained 200 messages per hour for several hours

Verify no drops and correct state per patient.

Out-of-order delivery

Integration engine retries and routing cause reordering:

  • A08 arrives before A01 for the same patient
  • A03 arrives before the A02 that preceded it
  • Duplicate A01 from an engine retry

The agent should buffer and reorder or apply updates idempotently.

Missing and malformed data

  • PID without IN1
  • PV1 with empty attending
  • A01 without DG1
  • PID-3 with malformed MRN

Log warnings, do not crash.

Cancel and correction

  1. A01 processed
  2. A11 arrives, agent reverses
  3. Corrected A01 arrives

Verify the reversal is clean and the corrected admission processes normally.

Building the test harness

Three components:

  • Message generator. Produces syntactically correct HL7v2 from patient templates and scenario scripts. Supports vendor profiles (Epic, Cerner, Meditech) with appropriate Z-segments.
  • MLLP sender. Sends messages to your agent with configurable timing. Handles ACKs, logs rejections.
  • Evaluation engine. After a scenario, queries agent state and compares to expected results. Turns scenarios into regression tests.

Start with single-patient journeys, then volume, then vendor variations.

Key Takeaways

  • HL7v2 ADT testing requires an MLLP listener, a message generator, vendor-specific templates, and scenario playback, not just a parser.
  • Test out-of-order delivery, burst volume, cancel/correction flows, and missing fields. These are the real production failure modes.
  • Z-segments carry operationally relevant data. Do not discard unknown segments in the parser.
  • Always ACK promptly. Slow ACKs trigger retries and duplicate processing that cascades into state bugs.
  • For why HL7v2 still matters even as FHIR grows, see why HL7v2 is not dead.

FAQ

How many HL7v2 messages does a typical hospital generate daily?

Large health systems commonly generate 200,000+ messages per day across ADT, ORU, and ORM feeds, with ADT accounting for a significant share. Burst rates at shift changes can exceed 500 messages per minute.

Do I need separate test harnesses per EHR vendor?

Yes, or a single harness with per-vendor message profiles. Epic, Cerner/Oracle Health, and Meditech each use distinct Z-segments and field conventions. Testing one does not validate the others.

What ACK modes should my agent support?

At minimum, original mode (AA, AE, AR in the MSA segment). Enhanced mode adds commit-level acks. Both are defined in the HL7v2 standard.

How does ADT testing relate to FHIR testing?

Most hospitals still run HL7v2 as the real-time event backbone, with FHIR layered on top. Your agent often needs both. ADT gives immediate event semantics (A01 on admission), while FHIR gives richer structured resources after the fact.

S
Stan Liu · Co-founder, Verial
·7 min read
Share