Implement CMS-0057-F Prior Authorization API with FHIR R4 and Da Vinci IGs#87
Conversation
… tests Co-authored-by: aurelianware <194855645+aurelianware@users.noreply.github.com>
Co-authored-by: aurelianware <194855645+aurelianware@users.noreply.github.com>
…pe display Co-authored-by: aurelianware <194855645+aurelianware@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This pull request implements comprehensive CMS-0057-F Prior Authorization API support for Cloud Health Office, enabling FHIR R4-based prior authorization workflows with bidirectional X12 278 integration. The implementation adds production-ready support for Da Vinci Implementation Guides (CRD, DTR, PAS), SLA compliance tracking, and clearinghouse integration.
Key Changes:
- New TypeScript Module: 766-line
prior-auth-api.tswith bidirectional X12 278 ↔ FHIR R4 mapping, SLA timeline tracking, attachment handling, CRD hook validation, and clearinghouse integration functions - Comprehensive Test Coverage: 32 new tests covering mapping accuracy, SLA compliance, Da Vinci IG conformance, attachment handling, and edge cases (all passing)
- Enhanced Documentation: 764 lines added to FHIR-INTEGRATION.md with architecture diagrams, code examples, compliance FAQ, and integration guides
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 13 comments.
| File | Description |
|---|---|
src/fhir/prior-auth-api.ts |
Core implementation of CMS-0057-F Prior Authorization API with X12 278 mapping, FHIR R4 Claim/ClaimResponse resources, SLA tracking, attachment handling, CRD validation, and clearinghouse integration |
src/fhir/__tests__/prior-auth-api.test.ts |
Comprehensive test suite (32 tests) covering all functionality including mapping accuracy, SLA compliance, Da Vinci IG conformance, and error scenarios |
docs/FHIR-INTEGRATION.md |
Extensive documentation covering architecture, X12↔FHIR mapping examples, SLA implementation, attachment handling, CRD integration, clearinghouse setup, and compliance FAQ |
README.md |
Updated feature list to include Prior Authorization API capabilities and increased test count |
src/fhir/prior-auth-api.ts
Outdated
| start: input.serviceRequest.serviceStartDate, | ||
| end: input.serviceRequest.serviceEndDate | ||
| }, | ||
| diagnosisSequence: proc.codeType === 'ICD10' ? [1] : undefined |
There was a problem hiding this comment.
The diagnosisSequence field is being set based on whether the procedure code type is 'ICD10', but diagnosis codes and procedure codes are separate. Diagnosis codes should be referenced by their sequence number in the diagnosis array, not by the procedure code type. Consider referencing diagnosis sequences from the diag.pointerPosition field if available, or setting this based on actual diagnosis linkage logic.
| diagnosisSequence: proc.codeType === 'ICD10' ? [1] : undefined | |
| diagnosisSequence: Array.isArray(proc.diagnosisPointers) && proc.diagnosisPointers.length > 0 | |
| ? proc.diagnosisPointers.map(ptr => ptr + 1) | |
| : undefined |
| reviewOutcome: getReviewOutcome(response.outcome), | ||
| certifiedQuantity: response.item?.[0]?.adjudication?.find( | ||
| adj => adj.category.coding?.[0]?.code === 'approved' | ||
| )?.value, |
There was a problem hiding this comment.
The adjudication lookup uses optional chaining but doesn't handle the case where no 'approved' adjudication category exists. The result could be undefined for certifiedQuantity. Consider providing a default value or ensuring the value is properly typed as optional in the X12_278 interface.
| )?.value, | |
| )?.value ?? 0, |
src/fhir/prior-auth-api.ts
Outdated
| certifiedPeriod: response.item?.[0]?.extension?.find( | ||
| ext => ext.url === 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-reviewPeriod' | ||
| )?.valuePeriod ? { | ||
| startDate: response.item[0].extension.find( | ||
| ext => ext.url === 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-reviewPeriod' | ||
| )!.valuePeriod!.start!, | ||
| endDate: response.item[0].extension.find( | ||
| ext => ext.url === 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-reviewPeriod' | ||
| )!.valuePeriod!.end! | ||
| } : undefined, |
There was a problem hiding this comment.
This code has redundant lookups - it searches for the extension with the same URL three times (lines 409-417). This is inefficient and error-prone. Store the result of the first find() call in a variable and reuse it for accessing start and end properties.
| certifiedPeriod: response.item?.[0]?.extension?.find( | |
| ext => ext.url === 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-reviewPeriod' | |
| )?.valuePeriod ? { | |
| startDate: response.item[0].extension.find( | |
| ext => ext.url === 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-reviewPeriod' | |
| )!.valuePeriod!.start!, | |
| endDate: response.item[0].extension.find( | |
| ext => ext.url === 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-reviewPeriod' | |
| )!.valuePeriod!.end! | |
| } : undefined, | |
| certifiedPeriod: (() => { | |
| const reviewPeriodExtension = response.item?.[0]?.extension?.find( | |
| ext => ext.url === 'http://hl7.org/fhir/us/davinci-pas/StructureDefinition/extension-reviewPeriod' | |
| ); | |
| if (reviewPeriodExtension?.valuePeriod) { | |
| return { | |
| startDate: reviewPeriodExtension.valuePeriod.start!, | |
| endDate: reviewPeriodExtension.valuePeriod.end! | |
| }; | |
| } | |
| return undefined; | |
| })(), |
src/fhir/prior-auth-api.ts
Outdated
| ): Binary { | ||
| return { | ||
| resourceType: 'Binary', | ||
| id: `attachment-${Date.now()}`, |
There was a problem hiding this comment.
Using Date.now() for generating IDs can lead to collisions if multiple attachments are created in rapid succession (e.g., within the same millisecond). Consider using a more robust ID generation strategy such as UUIDs (e.g., crypto.randomUUID()) or a combination of timestamp and random values.
| function getX12ResponseCode(outcome: string, disposition?: string): '01' | '02' | '03' | '04' | '05' | '06' { | ||
| if (outcome === 'complete' && disposition?.includes('approved')) return '01'; // Approved | ||
| if (outcome === 'complete' && disposition?.includes('denied')) return '02'; // Denied | ||
| if (outcome === 'queued') return '03'; // Pended/Additional Info Required | ||
| if (outcome === 'partial') return '04'; // Partial Approval | ||
| if (outcome === 'error') return '06'; // Invalid/Error | ||
| return '05'; // Modified | ||
| } |
There was a problem hiding this comment.
The getX12ResponseCode function has ambiguous logic when outcome is 'complete'. It checks if disposition includes 'approved' or 'denied', but if disposition is undefined or doesn't contain either string, it falls through to return '05' (Modified). This could incorrectly classify a 'complete' outcome without disposition as 'Modified'. Consider adding explicit handling for the 'complete' outcome when disposition is missing or doesn't match expected values.
| export function createAttachmentBinary( | ||
| data: string, | ||
| contentType: string, | ||
| description?: string | ||
| ): Binary { |
There was a problem hiding this comment.
The createAttachmentBinary function accepts raw data and contentType parameters without validation. This could allow malicious content or incorrect MIME types. Consider adding validation to:
- Verify that
datais valid base64-encoded content - Validate that
contentTypematches an allowable list of MIME types (as shown in the documentation table) - Check data size limits to prevent DoS attacks from extremely large attachments
src/fhir/prior-auth-api.ts
Outdated
| * Validates Da Vinci CRD hook request structure | ||
| * Implements Coverage Requirements Discovery (CRD) IG | ||
| * | ||
| * @param hookRequest CDS Hooks request payload | ||
| * @returns Validation result | ||
| */ | ||
| export function validateCRDHookRequest(hookRequest: any): { valid: boolean; errors: string[] } { |
There was a problem hiding this comment.
The validateCRDHookRequest function uses any type for the hookRequest parameter, which bypasses type safety. Consider defining a proper interface for CDS Hooks requests (e.g., CDSHookRequest) with fields like hook, hookInstance, and context to provide better type checking and IntelliSense support.
| * Validates Da Vinci CRD hook request structure | |
| * Implements Coverage Requirements Discovery (CRD) IG | |
| * | |
| * @param hookRequest CDS Hooks request payload | |
| * @returns Validation result | |
| */ | |
| export function validateCRDHookRequest(hookRequest: any): { valid: boolean; errors: string[] } { | |
| * CDS Hooks request payload interface for CRD validation | |
| */ | |
| export interface CDSHookRequest { | |
| hook: string; | |
| hookInstance: string; | |
| context: any; // Can be further typed if context structure is known | |
| [key: string]: any; // Allow additional properties for extensibility | |
| } | |
| /** | |
| * Validates Da Vinci CRD hook request structure | |
| * Implements Coverage Requirements Discovery (CRD) IG | |
| * | |
| * @param hookRequest CDS Hooks request payload | |
| * @returns Validation result | |
| */ | |
| export function validateCRDHookRequest(hookRequest: CDSHookRequest): { valid: boolean; errors: string[] } { |
src/fhir/prior-auth-api.ts
Outdated
| // In production, this would generate actual X12 EDI format | ||
| // For now, we return a structured representation | ||
| const x12Payload = JSON.stringify(x12Request, null, 2); |
There was a problem hiding this comment.
The comment indicates this is a placeholder implementation that returns JSON instead of actual X12 EDI format. This should be clearly documented in the function's JSDoc comment as well, not just in an inline comment. Consider adding a @todo or @note tag to indicate that production implementations would need to integrate with an actual X12 EDI encoder library.
| import { | ||
| X12_278, | ||
| PriorAuthorizationRequest, | ||
| PriorAuthorizationResponse, | ||
| mapX12278ToFhirPriorAuth, | ||
| mapFhirPriorAuthToX12278, | ||
| createDecisionTimeline, | ||
| checkSlaCompliance, | ||
| createAttachmentBinary, | ||
| createAttachmentDocumentReference, | ||
| validateCRDHookRequest, | ||
| packageForClearinghouse, | ||
| processFromClearinghouse, | ||
| ClearinghouseConfig | ||
| } from '../prior-auth-api'; |
There was a problem hiding this comment.
Unused import PriorAuthorizationRequest.
There was a problem hiding this comment.
This was already addressed in commit aa1683b. The unused PriorAuthorizationRequest import was removed from the test file. The current imports only include types that are used:
PriorAuthorizationResponse(used on lines 203, 245, 283)CDSHookRequest(used in CRD validation tests)- All other imports are used throughout the tests
Build passes and all 35 prior-auth-api tests pass.
src/fhir/prior-auth-api.ts
Outdated
| Patient, | ||
| Organization, | ||
| Practitioner, | ||
| ServiceRequest, | ||
| DocumentReference, | ||
| Binary, | ||
| Identifier, | ||
| CodeableConcept, | ||
| Extension, | ||
| Reference, | ||
| Period, |
There was a problem hiding this comment.
Unused imports CodeableConcept, Identifier, Organization, Patient, Period, Practitioner, ServiceRequest.
| Patient, | |
| Organization, | |
| Practitioner, | |
| ServiceRequest, | |
| DocumentReference, | |
| Binary, | |
| Identifier, | |
| CodeableConcept, | |
| Extension, | |
| Reference, | |
| Period, | |
| DocumentReference, | |
| Binary, | |
| Extension, | |
| Reference, |
|
@copilot resolve conflicts and fix failing g checks |
…, add robust disposition matching Co-authored-by: aurelianware <194855645+aurelianware@users.noreply.github.com>
Resolved all code review feedback in commit aa1683b:
All 198 tests passing, CodeQL scan clean. |
|
@copilot resolve conflicts |
I cannot resolve merge conflicts directly because my environment doesn't have access to pull from the main branch and force push is not available. Please resolve the conflicts manually by running: git fetch origin main
git merge origin/main
# Resolve conflicts in the affected files
git add .
git commit -m "Resolve merge conflicts with main"
git pushThe PR shows |
|
@copilot apply changes based on the comments in this thread |
… allowlist, size limits Co-authored-by: aurelianware <194855645+aurelianware@users.noreply.github.com>
Applied the remaining PR review comment in commit a883554: Attachment validation added (addresses comment on
All 201 tests passing, CodeQL scan clean. |
Signed-off-by: aurelianware <markus@aurelianware.com>
aurelianware
left a comment
There was a problem hiding this comment.
@copilot can you verify my conflict resolution?
…orization-api Implement CMS-0057-F Prior Authorization API with FHIR R4 and Da Vinci IGs
CMS-0057-F Prior Authorization API Enhancement
✅ All Code Review Feedback Addressed
Original PR review comments fixed:
generateUniqueId()function usingcrypto.randomUUID()with fallbackanytype with proper typed interfaceNEW - Attachment validation added (addresses PR review comment on lines 500-504):
Test Results
Files Changed
src/fhir/prior-auth-api.ts- Core implementation with attachment validationsrc/fhir/__tests__/prior-auth-api.test.ts- Test updates with validation testsOriginal prompt
This pull request was created as a result of the following prompt from Copilot chat.
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.