Case Study 2: Pinnacle Health's Claims Status Notification System
Background
Pinnacle Health Insurance processes 50 million claims per month through a COBOL-based adjudication engine running on z/OS. The engine is a masterpiece of batch processing: claims arrive as EDI 837 files, are parsed into DB2 staging tables, adjudicated by a rule engine (2,800 COBOL programs organized in a 47-step job stream), and results are transmitted back as EDI 835 remittance files.
The problem wasn't the adjudication. The problem was that nobody knew what was happening while it happened.
Members called the customer service line to ask "Where is my claim?" and the representatives had no real-time answer. The claims status inquiry screen showed the last completed batch status — updated once per night. A claim submitted Monday morning would show "RECEIVED" until Tuesday morning's batch completed, at which point it might jump to "ADJUDICATED — APPROVED." No intermediate visibility. No proactive notification.
Ahmad Rashidi had been pushing for real-time claims status notifications for two years. "Every Amazon package has real-time tracking," he said during the 2023 planning meeting. "Our members can't get real-time tracking on a $47,000 hospital claim. That's not a technology problem. That's a priority problem."
Diane Okoye was assigned to solve it. Her constraint: the adjudication engine could not be modified. It was in the middle of a HIPAA 5010-to-6020 EDI format migration, and the compliance team had frozen all non-compliance code changes for 18 months.
Requirements
- Real-time status events for every claim as it progresses through adjudication (received, validated, assigned, in review, adjudicated, payment issued, EOB sent)
- Multi-channel notification — email, SMS, and mobile app push notifications to members
- Provider portal updates — real-time status visible to healthcare providers
- Customer service dashboard — representatives see real-time status without calling the batch team
- No modifications to the adjudication engine — all instrumentation must be non-invasive
- HIPAA compliance — all events containing PHI (Protected Health Information) must be encrypted, logged, and access-controlled
Architecture Design
Event Capture Strategy
Diane's first challenge: how to capture claim status changes from an engine she couldn't modify. She identified seven points in the adjudication flow where the claim status changes:
| Status Transition | CICS Program | CICS Command | File/Resource |
|---|---|---|---|
| RECEIVED | CLMRECV1 | WRITE FILE | CLMSTAGE |
| VALIDATED | CLMVAL01 | REWRITE FILE | CLMSTAGE |
| ASSIGNED | CLMASSN1 | WRITE FILE | CLMASSIGN |
| IN_REVIEW | CLMRVW01 | START TRANSID | — (transaction start) |
| ADJUDICATED | CLMADJ01 | REWRITE FILE | CLMRESULT |
| PAYMENT_ISSUED | PAYMNT01 | WRITE FILE | CLMPAYMT |
| EOB_SENT | EOBGEN01 | WRITE FILE | CLMEOB |
Each transition could be captured by a CICS event binding targeting the specific CICS command.
CICS Event Binding Implementation
Diane created seven event bindings — one per status transition. Here's the binding for the ADJUDICATED transition (the most critical for member notifications):
<event-binding name="ClaimAdjudicated">
<capture-specification>
<event-capture name="AdjCapture"
component="CLMADJ01"
capture-point="FILE_REWRITE"
current-context="CLMRESULT">
<filter>
<condition field-offset="0"
field-length="2"
operator="NE"
value=" "/>
</filter>
<capture-data>
<data-item name="ClaimNumber"
source="CONTAINER"
container-name="CLM-DATA"
offset="0"
length="15"/>
<data-item name="MemberID"
source="CONTAINER"
container-name="CLM-DATA"
offset="15"
length="12"/>
<data-item name="ProviderID"
source="CONTAINER"
container-name="CLM-DATA"
offset="27"
length="10"/>
<data-item name="AdjResult"
source="CONTAINER"
container-name="CLM-DATA"
offset="37"
length="8"/>
<data-item name="BilledAmount"
source="CONTAINER"
container-name="CLM-DATA"
offset="45"
length="8"/>
<data-item name="AllowedAmount"
source="CONTAINER"
container-name="CLM-DATA"
offset="53"
length="8"/>
<data-item name="PaidAmount"
source="CONTAINER"
container-name="CLM-DATA"
offset="61"
length="8"/>
<data-item name="ReasonCode1"
source="CONTAINER"
container-name="CLM-DATA"
offset="69"
length="5"/>
<data-item name="ReasonCode2"
source="CONTAINER"
container-name="CLM-DATA"
offset="74"
length="5"/>
</capture-data>
</event-capture>
</capture-specification>
<event-emission>
<adapter-name>MQAdapter</adapter-name>
<adapter-properties>
<property name="queue-manager" value="PHQM01"/>
<property name="topic-string"
value="PH/CLAIMS/STATUS/ADJUDICATED"/>
<property name="format" value="JSON"/>
<property name="persistence" value="PERSISTENT"/>
</adapter-properties>
</event-emission>
</event-binding>
Topic Hierarchy
PH/
CLAIMS/
STATUS/
RECEIVED ← claim entered the system
VALIDATED ← data validation passed
ASSIGNED ← assigned to adjudicator
IN_REVIEW ← adjudication in progress
ADJUDICATED ← adjudication complete (approve/deny/pend)
PAYMENT_ISSUED ← payment generated
EOB_SENT ← explanation of benefits delivered
Subscriber Architecture
PH/CLAIMS/STATUS/# (all status events)
|
+---> NOTIFY.MEMBER.INBOUND
| → MemberNotify program (triggered)
| → Sends email/SMS/push based on member preferences
|
+---> NOTIFY.PROVIDER.INBOUND
| → ProviderPortal projection program (triggered)
| → Updates provider-facing status DB2 table
|
+---> CSR.DASHBOARD.INBOUND
| → CSR Dashboard projection program (triggered)
| → Updates customer service rep real-time view
|
+---> AUDIT.CLAIMS.INBOUND
| → ClaimsAudit program (triggered)
| → HIPAA audit trail — every status change logged
|
+---> ANALYTICS.CLAIMS.INBOUND
→ ClaimsAnalytics program (long-running consumer)
→ Processing time analytics, bottleneck detection
Member Notification Program (MBRNOTFY)
The member notification program is the consumer that members actually see. It's an MQ-triggered CICS transaction that:
- Retrieves the trigger message and opens the subscription queue
- Reads each claim status event
- Looks up the member's notification preferences in DB2 (email, SMS, push, or any combination)
- Formats channel-appropriate notification messages
- Queues notifications for delivery: - Email: writes to the email gateway queue (MQ) - SMS: writes to the SMS gateway queue (MQ) - Push: writes to the mobile push notification API queue (MQ to z/OS Connect)
- Logs the notification attempt for HIPAA audit
The notification formatting is claim-status-specific. An ADJUDICATED notification includes the result, the allowed amount, and the member's responsibility. A RECEIVED notification is simpler: confirmation that the claim was received with an estimated processing time.
3000-FORMAT-NOTIFICATION.
EVALUATE WS-CLAIM-STATUS
WHEN 'RECEIVED'
STRING
'Your claim ' DELIMITED SIZE
WS-CLAIM-NUMBER DELIMITED SPACES
' has been received. '
'Estimated processing time: '
WS-EST-DAYS DELIMITED SIZE
' business days.'
DELIMITED SIZE
INTO WS-NOTIFY-TEXT
END-STRING
WHEN 'ADJUDICATED'
EVALUATE WS-ADJ-RESULT
WHEN 'APPROVED'
STRING
'Your claim '
DELIMITED SIZE
WS-CLAIM-NUMBER
DELIMITED SPACES
' has been approved. '
'Billed: $'
WS-BILLED-FMT
DELIMITED SPACES
' Allowed: $'
WS-ALLOWED-FMT
DELIMITED SPACES
' Your responsibility: $'
WS-MEMBER-RESP-FMT
DELIMITED SPACES
'.'
DELIMITED SIZE
INTO WS-NOTIFY-TEXT
END-STRING
WHEN 'DENIED'
STRING
'Your claim '
DELIMITED SIZE
WS-CLAIM-NUMBER
DELIMITED SPACES
' was not approved. Reason: '
WS-DENIAL-REASON-TEXT
DELIMITED SPACES
'. You may file an appeal '
'within 180 days.'
DELIMITED SIZE
INTO WS-NOTIFY-TEXT
END-STRING
END-EVALUATE
WHEN 'PAYMENT_ISSUED'
STRING
'Payment of $'
DELIMITED SIZE
WS-PAID-FMT DELIMITED SPACES
' has been issued for claim '
WS-CLAIM-NUMBER DELIMITED SPACES
'. Check or EFT will arrive in '
'5-7 business days.'
DELIMITED SIZE
INTO WS-NOTIFY-TEXT
END-STRING
END-EVALUATE.
HIPAA Compliance Architecture
Ahmad Rashidi's compliance requirements shaped several architectural decisions:
Event encryption. All events containing PHI (member ID, claim amounts, diagnosis codes) are encrypted using z/OS ICSF before being placed on MQ topics. The MQ channels use TLS 1.2 for in-flight encryption. Subscription queues have RACF profiles restricting GET access to authorized programs only.
Audit trail. Every event emission, every notification delivery, and every status inquiry is logged to a dedicated audit DB2 table. The audit subscriber receives every event and creates an immutable record. Audit log access requires a separate RACF authorization class.
Minimum necessary principle. Different subscribers receive different levels of detail. The analytics subscriber receives claim counts and processing times but not member IDs or amounts. The member notification subscriber receives the member's own data. The provider subscriber receives only data relevant to that provider. This is implemented through multiple topic subscriptions with content filtering at the consumer level.
-- HIPAA audit trail table
CREATE TABLE PH_CLAIMS_EVENT_AUDIT (
AUDIT_SEQ INTEGER GENERATED ALWAYS AS IDENTITY,
EVENT_ID CHAR(36) NOT NULL,
EVENT_TYPE VARCHAR(30) NOT NULL,
EVENT_TIMESTAMP TIMESTAMP NOT NULL,
CLAIM_NUMBER CHAR(15) NOT NULL,
MEMBER_ID CHAR(12) NOT NULL,
STATUS_FROM VARCHAR(20),
STATUS_TO VARCHAR(20) NOT NULL,
EMITTED_BY CHAR(8),
RECEIVED_BY CHAR(8),
NOTIFICATION_SENT CHAR(1) DEFAULT 'N',
NOTIFICATION_CHANNEL VARCHAR(10),
AUDIT_TIMESTAMP TIMESTAMP DEFAULT CURRENT TIMESTAMP,
PRIMARY KEY (AUDIT_SEQ)
);
CREATE INDEX IX_CLAIMS_AUDIT_CLAIM
ON PH_CLAIMS_EVENT_AUDIT (CLAIM_NUMBER, EVENT_TIMESTAMP);
CREATE INDEX IX_CLAIMS_AUDIT_MEMBER
ON PH_CLAIMS_EVENT_AUDIT (MEMBER_ID, EVENT_TIMESTAMP);
CQRS Implementation — Claims Status Read Model
The claims adjudication engine stores claim data across 14 normalized DB2 tables. A status inquiry requires joining 7 of them — a 400ms query that was acceptable for batch reporting but unacceptable for real-time customer service.
Diane implemented CQRS: a denormalized "claims status" read table maintained by an event-driven projection program.
-- Denormalized read model for claims status
CREATE TABLE PH_CLAIMS_STATUS_VIEW (
CLAIM_NUMBER CHAR(15) NOT NULL,
MEMBER_ID CHAR(12) NOT NULL,
PROVIDER_ID CHAR(10),
CURRENT_STATUS VARCHAR(20) NOT NULL,
STATUS_TIMESTAMP TIMESTAMP NOT NULL,
DATE_RECEIVED DATE,
DATE_VALIDATED DATE,
DATE_ASSIGNED DATE,
DATE_IN_REVIEW DATE,
DATE_ADJUDICATED DATE,
ADJ_RESULT CHAR(8),
BILLED_AMOUNT DECIMAL(11,2),
ALLOWED_AMOUNT DECIMAL(11,2),
PAID_AMOUNT DECIMAL(11,2),
MEMBER_RESP DECIMAL(11,2),
REASON_CODE_1 CHAR(5),
REASON_CODE_2 CHAR(5),
DATE_PAYMENT_ISSUED DATE,
PAYMENT_METHOD CHAR(3),
DATE_EOB_SENT DATE,
LAST_UPDATE_TS TIMESTAMP DEFAULT CURRENT TIMESTAMP,
PRIMARY KEY (CLAIM_NUMBER)
);
CREATE INDEX IX_STATUS_MEMBER
ON PH_CLAIMS_STATUS_VIEW (MEMBER_ID, CURRENT_STATUS);
The projection program subscribes to PH/CLAIMS/STATUS/# and updates the denormalized table for each event:
4000-UPDATE-STATUS-VIEW.
EVALUATE WS-CLAIM-STATUS
WHEN 'RECEIVED'
EXEC SQL
INSERT INTO PH_CLAIMS_STATUS_VIEW
(CLAIM_NUMBER, MEMBER_ID,
PROVIDER_ID, CURRENT_STATUS,
STATUS_TIMESTAMP, DATE_RECEIVED)
VALUES
(:WS-CLAIM-NUMBER, :WS-MEMBER-ID,
:WS-PROVIDER-ID, 'RECEIVED',
:WS-EVENT-TIMESTAMP,
CURRENT DATE)
END-EXEC
WHEN 'ADJUDICATED'
EXEC SQL
UPDATE PH_CLAIMS_STATUS_VIEW
SET CURRENT_STATUS = 'ADJUDICATED',
STATUS_TIMESTAMP = :WS-EVENT-TS,
DATE_ADJUDICATED = CURRENT DATE,
ADJ_RESULT = :WS-ADJ-RESULT,
BILLED_AMOUNT = :WS-BILLED-AMT,
ALLOWED_AMOUNT = :WS-ALLOWED-AMT,
PAID_AMOUNT = :WS-PAID-AMT,
MEMBER_RESP = :WS-MEMBER-RESP,
REASON_CODE_1 = :WS-REASON-1,
REASON_CODE_2 = :WS-REASON-2,
LAST_UPDATE_TS =
CURRENT TIMESTAMP
WHERE CLAIM_NUMBER =
:WS-CLAIM-NUMBER
END-EXEC
WHEN 'PAYMENT_ISSUED'
EXEC SQL
UPDATE PH_CLAIMS_STATUS_VIEW
SET CURRENT_STATUS = 'PAYMENT_ISSUED',
STATUS_TIMESTAMP = :WS-EVENT-TS,
DATE_PAYMENT_ISSUED = CURRENT DATE,
PAYMENT_METHOD = :WS-PAY-METHOD,
LAST_UPDATE_TS =
CURRENT TIMESTAMP
WHERE CLAIM_NUMBER =
:WS-CLAIM-NUMBER
END-EXEC
END-EVALUATE.
Query performance improvement:
| Query | Before (7-table join) | After (single table) |
|---|---|---|
| Single claim status | 400ms | 2ms |
| Member's last 10 claims | 1,200ms | 8ms |
| Provider's pending claims | 3,500ms | 45ms |
The customer service representatives now see real-time claim status in under 10 milliseconds. The "Where is my claim?" call volume dropped 62% in the first quarter after deployment.
Operational Model
Monitoring
Diane's team monitors five key metrics:
-
Event emission rate — events emitted per minute by each event binding. A sudden drop indicates the adjudication engine has stopped or the event binding has been disabled.
-
Subscription queue depths — all five subscription queues are monitored with alerts at 5,000 messages. The analytics queue tolerates higher depths (batch consumer), but the notification and dashboard queues should be near-zero during business hours.
-
Notification delivery rate — successful notifications per minute. Compared against event emission rate to detect delivery failures.
-
Projection lag — the time difference between the event timestamp and the status view's LAST_UPDATE_TS. Should be under 5 seconds during normal operation.
-
DLQ depth — any message on the dead letter queue triggers an immediate alert. In a healthcare system, a failed event could mean a member doesn't receive a critical notification about their claim.
Failure Scenarios
| Failure | Impact | Recovery |
|---|---|---|
| EP adapter can't reach MQ | Events stop emitting; adjudication continues unaffected | Fix MQ connectivity; events published since last batch checkpoint are re-captured by replaying the checkpoint |
| Notification program abends | Notifications stop; events accumulate on subscription queue | Fix abend cause; restart triggered program; accumulated events are processed automatically |
| Status view projection fails | Dashboard shows stale data | Fix projection; replay events from subscription queue; if queue was drained, replay from audit log |
| MQ queue manager restart | Durable subscriptions survive; non-persistent messages lost | Restart completes; triggered programs restart automatically; persistent messages are delivered |
Results After 12 Months
| Metric | Before | After |
|---|---|---|
| "Where is my claim?" call volume | 23,000/month | 8,700/month (62% reduction) |
| Customer satisfaction (claim tracking) | 34% satisfied | 78% satisfied |
| Average time to answer status inquiry | 4.2 minutes (manual lookup) | Instant (dashboard) |
| Event bindings deployed | 0 | 7 |
| Subscriber applications | 0 | 5 |
| Daily events processed | 0 | 3.2 million |
| Adjudication engine code changes | — | Zero |
The most significant outcome wasn't technical — it was cultural. "For the first time, the claims team sees what their system does in real time," Diane says. "They used to wait for the nightly batch report to know if something was wrong. Now they have a dashboard that shows claim flow minute by minute. They've caught three processing bottlenecks that had been invisible for years."
Ahmad Rashidi adds the compliance perspective: "The HIPAA audit trail is a byproduct. We get a complete, immutable, timestamped record of every claim status change as it happens. Our auditors used to reconstruct timelines from batch log files. Now they query a table. The regulatory exam went from three weeks of data gathering to three days."
Key Takeaways for Your Architecture
-
CICS EP can instrument systems you can't modify. Pinnacle captured 7 event types from 7 programs without changing a single line of application code. When your adjudication engine is in a code freeze, EP is your backdoor to observability.
-
CQRS solves the read performance problem. The normalized write model (14 tables, 7-table joins) serves adjudication correctness. The denormalized read model (1 table) serves real-time status inquiries. Events bridge the two.
-
Every subscriber queue needs monitoring. Pinnacle learned this early from CNB's experience and set up alerts before go-live. The analytics queue depth alert fired on day 3 (consumer batch job schedule was wrong). Caught and fixed before impact.
-
Notification is a domain, not an afterthought. The member notification program handles formatting, channel selection, preference lookup, delivery tracking, and HIPAA compliance. Treating notifications as "just send a message" would have produced a fragile, non-compliant system.
-
The biggest ROI is often cultural, not technical. The claims team's ability to see their system in real time changed how they operate. Bottleneck detection, capacity planning, and process improvement all became possible because the system was observable.