PA BridgeResources

Health-IT engineers & architects · 2026-07-02

Testing the Dual Stack: Cross-Rail Lifecycle Cases Your QA Plan Is Missing

Every dual-rail prior authorization program has two test suites: one that proves the X12 278 path works, and one that proves the FHIR PAS path works. Both pass. Then production produces an authorization that was requested through PAS, extended through a 278, inquired about through both, and surfaced to the member through the Patient Access API — and the four systems disagree about what happened.

The unit of testing for a dual stack is not the transaction. It is the authorization lifecycle, and lifecycles do not respect rails. A provider's EHR may speak PAS while their billing service speaks 278; a delegated UM vendor may only emit 278 responses while your member-facing APIs are FHIR-native. Any authorization can change rails mid-life. If your QA plan has no cases that start on one rail and finish on the other, you are testing two products and shipping a third.

The cross-rail case catalog

These are concrete cases worth automating, each keyed to behavior the standards actually define.

1. Requested via PAS, extended via 278. Submit an initial request through the PAS Claim/$submit operation (a PAS Request Bundle in, a ClaimResponse Bundle out — the IG expects the round trip to complete synchronously, on the order of 15 seconds). Approve it. Then extend it the 278 way: a new 278 request with UM02 = 4 (extension) referencing the existing certification. Assert that the canonical record shows one authorization with a revised period, that a subsequent PAS $inquire returns the current state, and that the extension did not mint a second authorization. (On the FHIR rail the same intent is a PAS Claim Update revising the billable period or quantity; your mapping layer must recognize the two as the same operation.)

2. Cancelled on one rail, queried on the other. Cancel a PAS-originated auth using the 278's cancel semantics (UM02 = 3), then run a PAS inquiry. The PAS spec is specific here: the inquiry response must reflect current results for all items, including items changed or cancelled since the original request. Then invert it: cancel via a PAS Claim Update carrying the certificationType extension code 3, and confirm the 278 inquiry response shows the cancellation. Item-level cancels (the PAS infoCancelled modifier extension) deserve their own case — partial cancellation is where mapping layers quietly drop line items.

3. The replaced-authorization inquiry. The PAS IG requires that when an inquiry references a superseded reference number — because subsequent changes replaced it — the response returns the current authorization, even though it no longer carries the queried identifier. Build a case that revises an auth twice, queries by the original number, and asserts the current state comes back. This is exactly the scenario a provider's staff hits when they query from an old fax or portal printout.

4. preAuthRef / certification number consistency. One authorization, observed through every window: the 278 response's certification number, the PAS ClaimResponse's preAuthRef, the Patient Access API's PA resource, and eventually the 837 claim that cites it. Assert byte-for-byte identity — not "matches after trimming," not "same except a system prefix." Formatting drift here surfaces months later as claims-matching failures, which is why it merits its own standing test rather than an assertion buried in other cases.

5. Pend, then decide, across rails. Submit via PAS and force a pend (the 278 world's A4 — pended). The PAS flow expects the requester to learn of the final decision through a FHIR Subscription notification carrying a full response Bundle, with $inquire available for other systems. Deliver the final decision from the UM side as a 278 response (A1 certified in total, or A3 not certified), and assert three things: the subscription notification fires, the inquiry reflects the final HCR action code mapping, and the pend-to-decision interval lands in your turnaround metrics exactly once. Note the IG's own caveat: the inquiry response does not carry everything a submission response can (notably requests for additional information), so a client polling $inquire while pended can miss the ask — test that your stack surfaces the RFI through the subscription path.

6. Expedited flag fidelity. Urgency must survive translation. On the 278 the request's level-of-service code (UM06) marks it; in PAS the same data rides the levelOfServiceCode extension, bound to the same X12-maintained value set. Submit an expedited request on each rail and assert the other rail's view — and, more importantly, your SLA engine — classifies it expedited. A dropped urgency flag is not a cosmetic bug; it silently converts a 72-hour clock into a 7-day one.

7. Same auth in the Patient Access API. CMS-0057-F requires prior authorization data in the Patient Access API by January 2027. Every case above should end with the same assertion: the member-facing view shows the authorization's current status, decision, and reference. If your Patient Access pipeline is fed by a different projection than your provider-facing responses, this is where the divergence shows up first.

Test data: synthetic members, managed like code

Cross-rail cases need members, providers, coverage, and clinical context that exist consistently in every system under test — the EDI gateway, the FHIR server, the UM platform, the member API. That rules out both production data (PHI in test environments is a compliance finding, not a shortcut) and ad-hoc fixtures created per system.

Build a synthetic member panel as a versioned artifact: a few dozen members with deliberate variety — dependent vs subscriber, name edge cases, dual coverage, mid-lifecycle eligibility termination — plus a synthetic provider roster with in- and out-of-network entries. Generate each system's representation (X12 loops, FHIR resources, UM records) from one source of truth, so "member 014" means the same human everywhere. Two design notes from hard experience: give every synthetic member an unmistakably synthetic marker so a leak into a real pipeline is caught mechanically, and include members whose eligibility changes during an authorization's life, because rail-crossing plus eligibility churn is a genuinely nasty combination your happy-path panel will never exercise.

Regression strategy: your contract surface is versioned in three places

A dual stack's external contract changes when any of three things move: the Da Vinci IGs (PAS has published multiple STU versions, and CRD/DTR move on their own cadence), the X12 companion guides of your trading partners, and your own mapping layer. Treat all three as versioned inputs to the same regression suite:

  • Pin versions explicitly. Every test run should record which PAS IG version, which 278 TR3/companion-guide behavior set, and which mapping release it validated. "Passes" without versions is not evidence.
  • Isolate translation in contract tests. The FHIR-to-X12 mapping deserves its own fast test tier — resource in, segments out, and back — so an IG upgrade's blast radius is visible before the end-to-end suite runs.
  • Rerun the full cross-rail catalog on any version bump, including partner companion-guide changes that look cosmetic. Companion guides are where payer-specific 278 behavior lives, and "cosmetic" situational rules have a track record of moving reference numbers and code usage.
  • Keep a small always-on canary set in each non-prod partner environment — one submit-extend-inquire chain per rail pairing — so partner-side changes surface as canary failures, not as provider tickets.

The dual-rail era will last years, and the rails will keep versioning independently the whole time. Teams that treat cross-rail lifecycles as first-class test subjects — with a case catalog, a synthetic panel, and version-pinned regression — get boring, explainable releases. Teams that test each rail separately get to reverse-engineer lifecycle bugs from production claim rejections, one preAuthRef mismatch at a time.

Verify operation and extension behavior against the current Da Vinci PAS implementation guide and the X12 005010X217 TR3 plus your trading partners' companion guides; both rails' specifications continue to evolve.