Skip to content

API 55333 POA slack alerts#27776

Merged
siddharthalamsal merged 8 commits intomasterfrom
api-55333-POA-alerts
Apr 21, 2026
Merged

API 55333 POA slack alerts#27776
siddharthalamsal merged 8 commits intomasterfrom
api-55333-POA-alerts

Conversation

@siddharthalamsal
Copy link
Copy Markdown
Contributor

@siddharthalamsal siddharthalamsal commented Apr 15, 2026

Summary

Adds slack alerts for silent failures in v2 POA decide endpoint

  • validate_mapped_data!: when mapped data from BGS has errors
  • process_poa_decision: when processing the decision fails

Related issue(s)

API 55333
image

Testing done

  • New code is covered by unit tests

Manual testing in rails console (must have claims_api.slack setup in settings):

  1. Direct Call test
controller = ClaimsApi::V2::Veterans::PowerOfAttorney::RequestController.new
controller.send(:request_slack_alert, 'Console Test', "Manual test alert from rails console in #{Rails.env} at #{Time.current}")
  1. validate_mapped_data! test
controller = ClaimsApi::V2::Veterans::PowerOfAttorney::RequestController.new
controller.define_singleton_method(:params) { { id: 'test-validation-id' } }
controller.define_singleton_method(:claims_v2_logging) { |*args, **kwargs| puts "LOG: #{kwargs}" }
controller.define_singleton_method(:user_profile) { nil }
controller.define_singleton_method(:validate_form_2122_and_2122a_submission_values) { |**| ['field X is invalid'] }
controller.define_singleton_method(:validate_json_schema) { |*| raise JsonSchema::JsonApiMissingAttribute.new([{ 'type' => 'schema', 'data_pointer' => '/claimDate', 'schema_pointer' => '/additionalProperties' }]) }

begin
  controller.send(:validate_mapped_data!, '600000001', '2122', '091')
rescue Common::Exceptions::UnprocessableEntity
  puts 'UnprocessableEntity raised as expected — check Slack channel'
end
  1. process_poa_decision test
controller = ClaimsApi::V2::Veterans::PowerOfAttorney::RequestController.new
controller.define_singleton_method(:params) { { id: 'test-proc-decision-id' } }
controller.define_singleton_method(:claims_v2_logging) { |*| }

ClaimsApi::PowerOfAttorneyRequestService::DecisionHandler.define_method(:call) { raise StandardError, 'Simulated failure for Slack test' }

begin
  controller.send(
    :process_poa_decision,
    decision: 'acceptance', proc_id: 'fake-proc-id', representative_id: '12345',
    poa_code: '091', metadata: {},
    veteran: OpenStruct.new(participant_id: '600000001', icn: nil, mpi: OpenStruct.new(icn: nil)),
    claimant: OpenStruct.new(icn: nil, mpi: OpenStruct.new(icn: nil))
  )
rescue => e
  puts "Error raised: #{e.class} — check Slack channel"
end

ClaimsApi::PowerOfAttorneyRequestService::DecisionHandler.remove_method(:call)

You should see alerts like these in #vaapi-alerts-testing:
image

What areas of the site does it impact?

modules/claims_api/app/controllers/claims_api/v2/veterans/power_of_attorney/request_controller.rb
modules/claims_api/spec/controllers/v2/veterans/power_of_attorney/request_controller_spec.rb

Acceptance criteria

  • I fixed|updated|added unit tests and integration tests for each feature (if applicable).
  • No error nor warning in the console.
  • Events are being sent to the appropriate logging solution
  • Documentation has been updated (link to documentation)
  • No sensitive information (i.e. PII/credentials/internal URLs/etc.) is captured in logging, hardcoded, or specs
  • Feature/bug has a monitor built into Datadog (if applicable)
  • If app impacted requires authentication, did you login to a local build and verify all authenticated routes work as expected
  • I added a screenshot of the developed feature

@siddharthalamsal siddharthalamsal marked this pull request as ready for review April 15, 2026 18:35
@siddharthalamsal siddharthalamsal requested a review from a team as a code owner April 15, 2026 18:35
Copilot AI review requested due to automatic review settings April 15, 2026 18:35
@siddharthalamsal siddharthalamsal marked this pull request as draft April 15, 2026 18:35
@siddharthalamsal siddharthalamsal added the claimsApi modules/claims_api label Apr 15, 2026
@siddharthalamsal siddharthalamsal marked this pull request as ready for review April 15, 2026 18:35
@siddharthalamsal siddharthalamsal changed the title API 55333 API 55333 POA slack alerts Apr 15, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds Slack alerting for “silent failure” scenarios in the Claims API v2 POA decide flow so operational teams get notified when mapped BGS data validation fails or decision processing errors out.

Changes:

  • Adds poa_request_slack_alert helper and calls it from process_poa_decision rescue and mapped-data validation error handling.
  • Improves error-level logging and message detail for POA decision failures.
  • Adds specs covering Slack notification behavior and the new alerting paths.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
modules/claims_api/app/controllers/claims_api/v2/veterans/power_of_attorney/request_controller.rb Adds Slack alert helper + invokes it on decision-processing failures and mapped-data validation failures.
modules/claims_api/spec/controllers/v2/veterans/power_of_attorney/request_controller_spec.rb Adds unit coverage for Slack notifier helper and the new alerting behavior.

poa_request_slack_alert('POA Decide Request',
"Failed to process POA decision for id: #{params[:id]}, " \
"procId: #{proc_id} in #{Rails.env}: #{e.message}")
raise e
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

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

In this rescue block, raise e will reset the exception backtrace, which makes debugging production failures harder. Use raise to re-raise the current exception while preserving the original backtrace (and keep the Slack/logging behavior the same).

Suggested change
raise e
raise

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

end

def poa_request_slack_alert(source, message)
slack_client = SlackNotify::Client.new(webhook_url: Settings.claims_api.slack.webhook_url,
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

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

Settings.claims_api.slack.webhook_url should be treated as untrusted input (it may be nil or an unexpected type due to Parameter Store / env parsing). Consider coercing to a string with a safe fallback and skipping Slack notify when blank, so this method doesn’t raise/log errors repeatedly in environments where the webhook isn’t configured.

Suggested change
slack_client = SlackNotify::Client.new(webhook_url: Settings.claims_api.slack.webhook_url,
webhook_url = Settings.claims_api.slack.webhook_url.to_s.strip
return if webhook_url.blank?
slack_client = SlackNotify::Client.new(webhook_url: webhook_url,

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

Comment on lines +499 to +501
slack_client = SlackNotify::Client.new(webhook_url: Settings.claims_api.slack.webhook_url,
channel: '#api-benefits-claims-alerts',
username: "Failed #{source}")
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

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

PR description/manual testing notes mention alerts appearing in #vaapi-alerts-testing, but the code hard-codes channel: '#api-benefits-claims-alerts'. If the intended channel differs by environment, consider making the channel configurable (or update the PR description to match the actual target).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

this doest seem to effect anything for testing

Copy link
Copy Markdown
Contributor

@jeremyhunton-va jeremyhunton-va left a comment

Choose a reason for hiding this comment

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

LGTM! Fantastic testing plan!

number - 1
end

def poa_request_slack_alert(source, message)
Copy link
Copy Markdown
Contributor

@rockwellwindsor-va rockwellwindsor-va Apr 16, 2026

Choose a reason for hiding this comment

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

@siddharthalamsal This slack alert method could potentially be something we want to utilize elsewhere in the app at some point. Wondering what you thoughts would be on making this a module that we can include in this controller? Something like ClaimsApi::SlackNotifier etc. . We could rename the method as request_slack_alert it is not POA specific, we can keep the signature the same but then if we want to include this on other end points that could be failing silently it would be an easy update.

Thinking of a utilization along the lines of the claims_vs_logging . But it could just be included at that top level (application_controller) as a module, or just the method there just like the logging, that may also be enough given it is just the one method.

I realize it is a bit of a refactor to the work here. But worth it to perhaps get in place from the start instead of hoping the refactor comes in the future.

Let me know you think of the idea.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Great idea, I like the module plan, on it!

module V2
module Veterans
class PowerOfAttorney::RequestController < ClaimsApi::V2::Veterans::PowerOfAttorney::BaseController
class PowerOfAttorney::RequestController < ClaimsApi::V2::Veterans::PowerOfAttorney::BaseController # rubocop:disable Metrics/ClassLength
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd like to discourage disabling the rubocop here and instead keeping the class smaller. Refactoring this might fit in with Rockwell's suggestion.


# rubocop:disable Metrics/ParameterLists
def process_poa_decision(decision:, proc_id:, representative_id:, poa_code:, metadata:, veteran:, claimant:)
def process_poa_decision(decision:, proc_id:, representative_id:, poa_code:, metadata:, veteran:, claimant:) # rubocop:disable Metrics/MethodLength
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you refactor this method so it's more object oriented and less procedural? Just based on the comments, there could be a method to build headers, and a method to save the record.

(the main ask here is to avoid disabling rubocop.)

Copy link
Copy Markdown
Contributor

@rockwellwindsor-va rockwellwindsor-va Apr 16, 2026

Choose a reason for hiding this comment

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

Making ticket to refactor this further to remove the # rubocop:disable Metrics/ParameterLists disable as well. Tracked in API-55579

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 16, 2026

1 Warning
⚠️ This PR changes 365 lines of code (not counting whitespace/newlines, comments, or test files).

In order to ensure each PR receives the proper attention it deserves, we recommend not exceeding
200. Expect some delays getting reviews.

File Summary

Files

  • modules/claims_api/app/controllers/claims_api/v2/application_controller.rb (+1/-0)

  • modules/claims_api/app/controllers/claims_api/v2/veterans/power_of_attorney/request_controller.rb (+39/-151)

  • modules/claims_api/app/controllers/concerns/claims_api/slack_notifier.rb (+18/-0)

  • modules/claims_api/app/controllers/concerns/claims_api/v2/power_of_attorney_requests/create_validation.rb (+67/-0)

  • modules/claims_api/app/controllers/concerns/claims_api/v2/power_of_attorney_requests/index_validation.rb (+89/-0)

    Note: We exclude files matching the following when considering PR size:

    *.csv, *.json, *.tsv, *.txt, *.md, Gemfile.lock, app/swagger, modules/mobile/docs, spec/fixtures/, spec/support/vcr_cassettes/, modules/mobile/spec/support/vcr_cassettes/, db/seeds, modules/vaos/app/docs, modules/meb_api/app/docs, modules/appeals_api/app/swagger/, *.bru, *.pdf, modules/*/spec/fixtures/*, modules/*/spec/factories/*, modules/*/spec/**/*.rb, spec/**/*.rb, modules/*/docs/**/*.yaml, modules/*/docs/**/*.yml, modules/*/app/docs/**/*.yaml, modules/*/app/docs/**/*.yml
    

Big PRs are difficult to review, often become stale, and cause delays.

Generated by 🚫 Danger

def validate_page_size_and_number_params
return if use_defaults?

valid_page_param?('size') if params[:page][:size]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[reek] reported by reviewdog 🐶
DuplicateMethodCall: ClaimsApi::V2::PowerOfAttorneyRequests::IndexValidation#validate_page_size_and_number_params calls 'params[:page]' 6 times [https://github.com/troessner/reek/blob/v6.5.0/docs/Duplicate-Method-Call.md]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done


def normalize(item)
item.to_s.strip.downcase
def build_bgs_attributes(form_attributes)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is showing up as new code in the git diff, but it originally was in this file (see removed chunk above), i moved it to the new file to reduces total lines, but then that file had too many lines so i moved it back 🙃

@rockwellwindsor-va
Copy link
Copy Markdown
Contributor

giving this 👀 now

message: 'Encountered issues validating the mapped data')
level: :error,
message: "Encountered issues validating the mapped data for POA id: #{params[:id]}: " \
"#{@claims_api_forms_validation_errors}")
Copy link
Copy Markdown
Contributor

@rockwellwindsor-va rockwellwindsor-va Apr 20, 2026

Choose a reason for hiding this comment

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

I'm not actually gettin the text in the error log I was hoping for. I think we need an update to the log_and_raise_decision_error_message bit for the JsonSchema::JsonApiMissingAttribute. to include the error messages text so wee can see that.

Something along these lines (pseudo code here just FYI)

          # JSON validations, all errors, including errors from the custom validations
          # will be raised here if JSON errors exist
          validate_json_schema(type.upcase)
          # otherwise we raise the errors from the custom validations if no JSON
          # errors exist
          log_and_raise_decision_error_message!(@claims_api_forms_validation_errors)
        rescue JsonSchema::JsonApiMissingAttribute => e
          log_and_raise_decision_error_message!(e.to_json_api)
        end

I'm not a huge fan of passing in the instance variable for the errors, seems odd but I think we need to send in the errors since it would be one or the other. This would look like this which I think helps us understand the error more, otherwise we know it is a 422, but have no idea why.

Image

@rockwellwindsor-va
Copy link
Copy Markdown
Contributor

Giving this 👀 now

Copy link
Copy Markdown
Contributor

@rockwellwindsor-va rockwellwindsor-va left a comment

Choose a reason for hiding this comment

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

Log out looked good, submissions ran as expected,thanks for making that update, this looked good to me

Image

@siddharthalamsal siddharthalamsal merged commit a921312 into master Apr 21, 2026
42 of 43 checks passed
@siddharthalamsal siddharthalamsal deleted the api-55333-POA-alerts branch April 21, 2026 16:18
balexandr pushed a commit that referenced this pull request Apr 21, 2026
* add alerts for silent failures

* copilot changes

* SlackNotifier module

* refactor

* remove duplicate method calls

* update logging
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

claimsApi modules/claims_api

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants