Correspondence Auto Assign - department-of-veterans-affairs/caseflow GitHub Wiki

Auto-assign algorithm

The following is how Correspondences are auto-assigned to Mail Team Users and Mail Superusers within the Inbounds Ops Team. Only Inbound Ops Team admin users will able to view and click the Auto assign correspondences button on the /queue/correspondence page under the "Unassigned" tab.

UML Diagrams

  1. BatchAutoAssignmentAttempts
image

2. CorrespondenceAutoAssignmentLevers
image

Frontend

Correspondence Cases - Unassigned tab

The button is currently implemented in client/app/queue/correspondence/component/BatchAutoAssignButton.jsx and renders only when the user is a member of the Inbound Ops Team and has the authority to bulk assign. Only admin users can bulk assign.

AutoAssignAlertBanner

The client/app/queue/correspondence/component/AutoAssignAlertBanner.jsx component handles how information from BatchAutoAssignmentAttempts are displayed to the client.

After the "Auto assign correspondences" button is clicked, it will immediately begin polling the backend at correspondence_controller#auto_assign_status every 30 seconds until either a completed or failed status is returned. While polling is initiated the Auto Assign button will be disabled.

This component uses Redux, specifically the setAutoAssignmentAlertBanner() to handle the banner state and fetchAutoAssignBannerInfo() to handle the API calls. Whenever an API changes the alertBanner redux state and displays a banner, a useEffect runs to re-enable the button and clear the polling interval. The API calls only occur when there is a BatchAutoAssignmentId set by the BatchAutoAssignButton.jsx in the redux store.

There are currently 3 banners used: success, info, and error banners.

  1. The success banner will display the user that completed status of the job along with the number of correspondences successfully assigned.
  2. The info banner displays algorithm check failures.
  3. The error banner displays all other errors; full error details are logged to Sentry.

BatchAutoAssignButton

The BatchAutoAssignButton.jsx component is responsible for making the API call to GET correspondence_controller#auto_assign_correspondence. It will then receive the BatchAutoAssignmentAttempt.id from the backend and store it in Redux, as well as disable the button.

Backend

CMP Integration

This will occur when at least one package comes from CMP and after it is transformed into a Correspondence object within Caseflow.

Algorithm

  1. Create a database record in BatchAutoAssignmentAttempt for this batch auto-assignment attempt
  2. Get list of Correspondences for auto-assignment which depends on where process started at:
    1. If started in "Correspondence Cases - Unassigned tab"
      1. Find list of correspondences with unassigned ReviewPackageTasks
        1. Sort correspondences by VA DOR ascending so the oldest correspondences are assigned out first
    2. If started in CMP Integration
      1. Use the Correspondence(s) that were created from CMP package data
  3. If no correspondences were found auto-assignment is done:
    1. EXIT POINT
    2. Update the BatchAutoAssignmentAttempt with a status that indicates no eligible correspondences were found
  4. Find all Mail Team Users and Mail Superusers who have an assigned count lower than the maximum (as defined by CorrespondenceAutoAssignmentLever.max_capacity) ordered by lowest assigned count then by waiting longest for a new correspondence
    1. The capacity for Mail Team Users is determined by the number of ReviewPackageTasks assigned to a user with the status of "assigned, "in progress", or "on hold".
    2. The capacity for Mail Superusers is determined by the sum of the following values
      1. The number of ReviewPackageTasks assigned to a user with the status of "assigned", "in progress", or "on hold".
      2. Total number of Pending Reassign/Split/Merge Request tasks with a status of "assigned" divided by total number of Mail Superusers
        1. This is to account for additional work that Mail Supervisors do
  5. Order user list by assigned count and who has been waiting the longest so that users with the least amount assigned and have been waiting the longest will get assigned correspondences first
    1. Important user properties include
      1. Capacity
      2. Can work NOD ("notice of dispute") mail
      3. Last time was assigned correspondences
  6. Since the auto-assignment job can be triggered multiple ways, the query to select eligible users is re-run for each correspondence in order to avoid using a local cache of the data that could be stale.
  7. If no eligible users were found auto-assignment is done:
    1. EXIT POINT
    2. Update the BatchAutoAssignmentAttempt with a status that indicates no eligible users were found
  8. If eligible users were found, the algorithm loops through this list of "candidate assignees", returning the first eligible assignee for assignment using the following logic:
    1. Guard clause: If the correspondence is NOD and the candidate assignee does NOT have NOD permissions, continue; else...
    2. Check if the candidate assignee has a sensitivity level >= the sensitivity level of the correspondence's veteran
      1. The BGSService is used to check the BGS API for user/veteran sensitivity levels
    3. If the candidate assignee's sensitivity level is >= the correspondence's veteran's sensitivity level, return the candidate assignee; else, continue looping through the list of candidate assignees until either:
      1. An eligible assignee is found, or
      2. The list of candidate assignees is exhausted, at which point the algorithm returns nil
  9. The algorithm handles the return value of the check for assignable users:
    1. If an eligible assignee is returned, the returned user is assigned to the correspondence, or
    2. If no eligible assignee was found, the algorithm continues looping through unassigned correspondences
    3. Either way, the result of this assignment attempt is stored to the IndividualAutoAssignmentAttempt table.
  10. The algorithm continues looping through all unassigned correspondences until one of the possible end conditions is met:
    1. All unassigned correspondences are assigned, or
    2. There are no more users available for assignment
  11. After all correspondences have been assigned or no more users are eligible for assignment the BatchAutoAssignmentAttempt record is updated with stats about the auto-assignment run.
    1. If an error occurs at any point during the auto assignment run, the BatchAutoAssignmentAttempt record is updated with information about the error encountered.

AutoAssignCorrespondenceJob

When the Auto Assign Correspondences button is clicked, an AutoAssignCorrespondenceJob will be enqueued through GET correspondence_controller#auto_assign_correspondence. This job will run async in production environment and synchronously in lower development and testing environments.

The backend will use the current_user to create a BatchAutoAssignmentAttempt, and will pass the batch_auto_assignment_attempt_id and current_user_id to the AutoAssignCorrespondenceJob. The AutoAssignCorrespondenceJob will then run the CorrespondenceAutoAssigner with the same parameters. The entirety of the technical implementation of the business logic outlined in the auto assign algorithm is performed through the CorrespondenceAutoAssigner service (which utilizes several other services; see below).

CorrespondenceAutoAssignRunVerifier

Before an auto assign job is run, the CorrespondenceAutoAssignRunVerifier performs a few checks in order to:

  • Prevent a run if certain feature toggles are enabled/disabled
  • Prevent a run if job parameters are invalid
  • Prevent a run if another auto assign job is already running (in order to prevent race conditions)

CorrespondenceAutoAssigner

The primary responsibility of the CorrespondenceAutoAssigner service is to initialize the CorrespondenceAutoAssignLogger and perform all the necessary requirement checks, data extraction, and data transformation before assignment occurs.

The checks are:

  1. Unassigned Correspondences - Checks to ensure the total number ReviewPackageTasks with a status of unassigned is greater than 0
    1. See correspondence_auto_assigner#unassigned_review_package_tasks
  2. Assignable Users - Checks to ensure that there are users whose capacity level is < max capacity and who can handle NOD related correspondences
  3. Sensitivity Level - Before each unassigned correspondence is assigned to an assignable user, a BGS (Benefits Gateway Service) call is made to ensure the assignable user has the proper access rights to the unassigned correspondence

NOTE** All business logic regarding user-related checks in list items 2 and 3 above are delegated to the AutoAssignableUserFinder.rb service

CorrespondenceAutoAssignLogger

The primary responsibility of the CorrespondenceAutoAssignLogger is to handle write operations for BatchAutoAssignmentAttempts and IndividualAutoAssignmentAttempts, and keeps track of the total number of assigned and unassigned packages and NOD packages.

After a job is processed, the logger will update the status and statistics column detailing the result, time elapsed, and other useful information.

BatchAutoAssignmentAttempt & IndividualAutoAssignmentAttempt

The BatchAutoAssignmentAttempt object records the status of a running job and contains details on the statistics related to the job, and has a one to many relationship with IndividualAutoAssignmentAttempt.

The AutoAssignable concern handles validation of the status field.

AutoAssignableUserFinder

Given a correspondence that needs to be assigned, the AutoAssignableUserFinder will return the first eligible assignable user or nil if no eligible assignable users exist for the given correspondence.

Key Methods:

auto_assignable_user_finder#get_first_assignable_user - Returns an the first User that meets the eligibility criteria for the given correspondence. Each user is mapped to an AssignableUser Struct to attach additional information that will be related to checks and sorting. This includes the number of assigned correspondences, whether the User can access NODs, and when the user was last assigned a correspondence.

To avoid incorrect assignments made due to cached data, the database is used as the source of truth for available assignable users and thus there is no manual caching of DB results.

⚠️ **GitHub.com Fallback** ⚠️