Skip to content
This repository is currently being migrated. It's locked while the migration is in progress.
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,7 @@ Brewfile @department-of-veterans-affairs/backend-review-group
clamav_tmp/ @department-of-veterans-affairs/backend-review-group
config/application.rb @department-of-veterans-affairs/backend-review-group
config/audit_log/user_action_events.yml @department-of-veterans-affairs/octo-identity
config/benefits_claims @department-of-veterans-affairs/benefits-management-tools-be @department-of-veterans-affairs/backend-review-group
config/betamocks @department-of-veterans-affairs/backend-review-group
config/betamocks/services_config.yml @department-of-veterans-affairs/backend-review-group
config/boot.rb @department-of-veterans-affairs/backend-review-group
Expand Down Expand Up @@ -914,6 +915,7 @@ lib/apps @department-of-veterans-affairs/vfs-facilities-frontend @department-of-
lib/backend_services.rb @department-of-veterans-affairs/backend-review-group
lib/bb @department-of-veterans-affairs/vfs-vaos @department-of-veterans-affairs/backend-review-group
lib/benefits_claims/concerns/multi_provider_base.rb @department-of-veterans-affairs/benefits-management-tools-be @department-of-veterans-affairs/backend-review-group
lib/benefits_claims/claim_status_meta @department-of-veterans-affairs/benefits-management-tools-be @department-of-veterans-affairs/backend-review-group
lib/benefits_claims/providers @department-of-veterans-affairs/benefits-management-tools-be @department-of-veterans-affairs/backend-review-group
lib/benefits_claims/responses/claim_response.rb @department-of-veterans-affairs/benefits-management-tools-be @department-of-veterans-affairs/backend-review-group
lib/benefits_claims/title_generator.rb @department-of-veterans-affairs/benefits-management-tools-be @department-of-veterans-affairs/backend-review-group
Expand Down Expand Up @@ -1580,6 +1582,7 @@ spec/helpers/parameter_filter_helper_spec.rb @department-of-veterans-affairs/bac
spec/initializers/rails_semantic_logger_patch_spec.rb @department-of-veterans-affairs/backend-review-group
spec/lib/apps @department-of-veterans-affairs/lighthouse-pivot
spec/lib/bb @department-of-veterans-affairs/vfs-vaos @department-of-veterans-affairs/backend-review-group
spec/lib/benefits_claims/claim_status_meta @department-of-veterans-affairs/benefits-management-tools-be @department-of-veterans-affairs/backend-review-group
spec/lib/benefits_claims/providers @department-of-veterans-affairs/benefits-management-tools-be @department-of-veterans-affairs/backend-review-group
spec/lib/benefits_claims/responses/claim_response_spec.rb @department-of-veterans-affairs/benefits-management-tools-be @department-of-veterans-affairs/backend-review-group
spec/lib/benefits_claims/title_generator_spec.rb @department-of-veterans-affairs/benefits-management-tools-be @department-of-veterans-affairs/backend-review-group
Expand Down
13 changes: 11 additions & 2 deletions app/controllers/v0/concerns/multi_provider_support.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ module MultiProviderSupport
extend ActiveSupport::Concern
include BenefitsClaims::Concerns::MultiProviderBase

LEGACY_PROVIDER_TYPE_ALIASES = {
'ivcchampvabenefitsclaimsprovider' => 'ivc_champva'
}.freeze

private

def format_error_entry(provider_name, message)
Expand Down Expand Up @@ -93,8 +97,8 @@ def provider_registry
end

def provider_class_for_type(type)
normalized_type = type.to_s.downcase
provider = provider_registry.find { |p| p[:name].to_s == normalized_type }
provider_type = normalized_provider_type(type)
provider = provider_registry.find { |p| p[:name].to_s == provider_type }

raise Common::Exceptions::InvalidFieldValue.new('type', type) if provider.nil?

Expand Down Expand Up @@ -129,6 +133,11 @@ def provider_type_from_class(provider_class)

provider[:name].to_s
end

def normalized_provider_type(type)
normalized_type = type.to_s.downcase
LEGACY_PROVIDER_TYPE_ALIASES.fetch(normalized_type, normalized_type)
end
end
end
end
103 changes: 103 additions & 0 deletions config/benefits_claims/claim_status_meta/ivc_champva/default.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
{
"detail": {
"pageTitle": "Application for CHAMPVA benefits",
"sectionTitle": "Applicants"
},
"statusHeader": {
"label": "Application status",
"intro": "Here's the latest update on your application."
},
"whatYouNeedToDo": {
"title": "What you need to do",
"emptyState": "You don't need to do anything right now. If there's an update, we'll mail you a letter."
},
"files": {
"simpleLayout": true,
"headerTitle": "Application files",
"description": "If you need to add information or update your documents, you can print a copy of each document and send them by mail or fax.",
"sectionTitle": "Application files",
"introText": "If you need to add information or update your documents, you can print a copy of each document and send them by mail or fax.",
"noteText": "We can only scan 1 side of each document. If any of your documents are double-sided, you'll need to include copies of each side of those documents.",
"options": {
"mail": {
"title": "Option 1: By mail",
"description": "Mail copies of your documents to this address:",
"addressLines": [
"VHA Office of Community Care",
"CHAMPVA Eligibility",
"PO Box 137",
"Spring City, PA 19475"
]
},
"fax": {
"title": "Option 2: By fax",
"description": "Fax your documents to 1-303-331-7809."
}
},
"confirmation": {
"title": "How to confirm we've received your documents",
"description": "To confirm we've received documents you submitted by mail or fax, call us at 800-733-8387 (TTY: 711). We're here Monday through Friday, 8:00 a.m. to 7:30 p.m. ET."
}
},
"help": {
"phone": "8007338387",
"tty": "711",
"hours": "Monday through Friday, 8:00 a.m. to 7:30 p.m. ET.",
"intro": "If you have questions about your CHAMPVA application, call us"
},
"overview": {
"title": "Overview of the application process",
"description": "Track where you are in the application process for CHAMPVA benefits. And learn what to expect at each step.",
"currentStepPrefix": "Your application moved to this step on",
"steps": [
{
"phase": 1,
"header": "Step 1: Application received",
"description": "We received your application.",
"details": [
"If we need more information, we'll mail you a letter."
],
"linkText": "Learn more about what to do after you apply for CHAMPVA benefits",
"linkUrl": "https://www.va.gov/health-care/family-caregiver-benefits/champva/"
},
{
"phase": 2,
"header": "Step 2: Application decided",
"description": "We made a decision on your application.",
"details": [
"We'll send you a decision letter for each applicant by mail. They should arrive within 7 to 10 business days."
]
}
],
"currentStepByStatus": {
"pending": 1,
"vbms": 2,
"error": 2
}
},
"listCard": {
"title": "Application for CHAMPVA benefits",
"receivedLabel": "Received on",
"lastUpdatedPrefix": "Last updated:"
},
"whatWeAreDoing": {
"title": "What we're doing",
"linkText": {
"status": "Learn more about this step"
},
"statusMap": {
"pending": {
"title": "Step 1 of 2: Application received",
"description": "We received your application. If we need more information, we'll mail you a letter."
},
"vbms": {
"title": "Step 2 of 2: Application completed",
"description": "We completed processing your application."
},
"error": {
"title": "Step 2 of 2: Additional review needed",
"description": "We need additional review before we can complete your application."
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
{
"detail": {
"sectionTitle": "What you've claimed"
},
"statusHeader": {
"label": "Claim status",
"intro": "Here's the latest information on your claim."
},
"whatYouNeedToDo": {
"title": "What you need to do",
"emptyState": "There's nothing we need from you right now. We'll let you know when there's an update."
},
"help": {
"phone": "8008271000",
"tty": "711",
"hours": "Monday through Friday, 8:00 a.m. to 9:00 p.m. ET.",
"intro": "Call us"
},
"whatWeAreDoing": {
"title": "What we're doing",
"linkText": {
"phaseType": "Learn more about this step",
"status": "Learn more about the review process"
},
"phaseTypeMap": {
"CLAIM_RECEIVED": {
"title": "Step 1 of 8: Claim received",
"description": "We received your claim in our system."
},
"UNDER_REVIEW": {
"title": "Step 2 of 8: Initial review",
"description": "We're checking your claim for basic information, like your name and Social Security number. If information is missing, we'll contact you."
},
"GATHERING_OF_EVIDENCE": {
"title": "Step 3 of 8: Evidence gathering",
"description": "We're reviewing your claim to make sure we have all the evidence and information we need. If we need anything else, we'll contact you."
},
"REVIEW_OF_EVIDENCE": {
"title": "Step 4 of 8: Evidence review",
"description": "We're reviewing all the evidence for your claim. If we need more evidence or you submit more evidence, your claim will go back to Step 3: Evidence gathering."
},
"PREPARATION_FOR_DECISION": {
"title": "Step 5 of 8: Rating",
"description": "We're deciding your claim and determining your disability rating. If we need more evidence or you submit more evidence, your claim will go back to Step 3: Evidence gathering."
},
"PENDING_DECISION_APPROVAL": {
"title": "Step 6 of 8: Preparing decision letter",
"description": "We're preparing your decision letter. If we need more evidence or you submit more evidence, your claim will go back to Step 3: Evidence gathering."
},
"PREPARATION_FOR_NOTIFICATION": {
"title": "Step 7 of 8: Final review",
"description": "A senior reviewer is doing a final review of your claim and the decision letter."
},
"COMPLETE": {
"title": "Step 8 of 8: Claim decided",
"description": "You can view and download your decision letter. We also sent you a copy by mail."
}
},
"statusMap": {
"CLAIM_RECEIVED": {
"title": "Step 1 of 5: Claim received",
"description": "We received your claim. We haven't assigned the claim to a reviewer yet."
},
"INITIAL_REVIEW": {
"title": "Step 2 of 5: Initial review",
"description": "We assigned your claim to a reviewer. The reviewer will determine if we need any more information from you."
},
"EVIDENCE_GATHERING_REVIEW_DECISION": {
"title": "Step 3 of 5: Evidence gathering, review, and decision",
"description": "We're getting evidence from you, your health care providers, government agencies, and other sources. We'll review the evidence and make a decision."
},
"PREPARATION_FOR_NOTIFICATION": {
"title": "Step 4 of 5: Preparation for notification",
"description": "We've made a decision on your claim. We're getting your decision letter ready to mail to you."
},
"COMPLETE": {
"title": "Step 5 of 5: Closed",
"description": "We've made a decision about your claim. If available, you can view your decision letter. We'll also send you your letter by U.S. mail."
}
}
}
}
4 changes: 4 additions & 0 deletions config/features.yml
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,10 @@ features:
actor_type: user
description: When enabled, use the multi-provider registry to fetch claims from configured providers.
enable_in_development: true
cst_champva_custom_content:
actor_type: user
description: When enabled, include CHAMPVA-specific claim status metadata content in benefits claims responses.
enable_in_development: true
cst_multi_claim_provider_mobile:
actor_type: user
description: For mobile app, when enabled, use the multi-provider registry to fetch claims from configured providers
Expand Down
14 changes: 7 additions & 7 deletions config/initializers/benefits_claims_providers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

require 'benefits_claims/providers/provider_registry'
require 'benefits_claims/providers/lighthouse/lighthouse_benefits_claims_provider'
require 'benefits_claims/providers/ivc_champva/ivc_champva_benefits_claims_provider'

BenefitsClaims::Providers::ProviderRegistry.register(
:lighthouse,
Expand All @@ -10,10 +11,9 @@
enabled_by_default: false
)

# Future providers can be registered here:
# BenefitsClaims::Providers::ProviderRegistry.register(
# :champva,
# BenefitsClaims::Providers::Champva::ChampvaBenefitsClaimsProvider,
# feature_flag: 'benefits_claims_champva_provider',
# enabled_by_default: false
# )
BenefitsClaims::Providers::ProviderRegistry.register(
:ivc_champva,
BenefitsClaims::Providers::IvcChampva::IvcChampvaBenefitsClaimsProvider,
feature_flag: 'benefits_claims_ivc_champva_provider',
enabled_by_default: false
)
46 changes: 46 additions & 0 deletions lib/benefits_claims/claim_status_meta/config_loader.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# frozen_string_literal: true

require 'json'

module BenefitsClaims
module ClaimStatusMeta
class ConfigLoader
BASE_PATH = Rails.root.join('config', 'benefits_claims', 'claim_status_meta')

class << self
def load(provider:, variant: 'default')
provider_name = provider.to_s
variant_name = variant.to_s
config = if Rails.env.development? || Rails.env.test?
parse_config(provider_name, variant_name)
else
cached_config(provider_name, variant_name)
end

# Callers may mutate values (for dynamic fields); always return a copy.
config.deep_dup
end

private

def cached_config(provider_name, variant_name)
Rails.cache.fetch("benefits_claims/claim_status_meta/#{provider_name}/#{variant_name}") do
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rails.cache.fetch here has no TTL or deploy/versioned cache key. In production cache stores (Redis/Memcached), this can cause stale JSON metadata to survive deploys/updates. Consider adding expires_in and/or incorporating the file mtime/app version into the cache key to ensure new JSON content takes effect predictably.

Suggested change
Rails.cache.fetch("benefits_claims/claim_status_meta/#{provider_name}/#{variant_name}") do
file_path = BASE_PATH.join(provider_name, "#{variant_name}.json")
file_version = File.exist?(file_path) ? File.mtime(file_path).to_i : 'missing'
cache_key = "benefits_claims/claim_status_meta/#{provider_name}/#{variant_name}/#{file_version}"
Rails.cache.fetch(cache_key, expires_in: 1.hour) do

Copilot uses AI. Check for mistakes.
parse_config(provider_name, variant_name).freeze
end
end

def parse_config(provider_name, variant_name)
file_path = BASE_PATH.join(provider_name, "#{variant_name}.json")
raise ArgumentError, "Claim status metadata file not found: #{file_path}" unless File.exist?(file_path)

parsed = JSON.parse(File.read(file_path))
raise ArgumentError, "Claim status metadata must be a JSON object: #{file_path}" unless parsed.is_a?(Hash)

parsed
rescue JSON::ParserError => e
raise ArgumentError, "Invalid JSON in claim status metadata file #{file_path}: #{e.message}"
end
end
end
end
end
9 changes: 6 additions & 3 deletions lib/benefits_claims/concerns/multi_provider_base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def get_claim_from_providers(claim_id)
configured_providers.each do |provider_class|
provider = provider_class.new(@current_user)
response = provider.get_claim(claim_id)
return response if validate_claim_response(response)
return response if validate_claim_response(response, claim_id)
rescue Common::Exceptions::RecordNotFound
log_claim_not_found(provider_class)
rescue Common::Exceptions::Unauthorized, Common::Exceptions::Forbidden => e
Expand All @@ -91,8 +91,11 @@ def get_claim_from_providers(claim_id)
raise Common::Exceptions::RecordNotFound, claim_id
end

def validate_claim_response(response)
response && response['data']
def validate_claim_response(response, requested_claim_id)
data = response&.dig('data')
return false unless data

data['id'].to_s == requested_claim_id.to_s
end

def log_claim_not_found(provider_class)
Expand Down
Loading
Loading