Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chairman Mason Priority: Create Auto-Distribution Job for Priority Cases #14604

Closed
13 tasks
araposo-tistatech opened this issue Jun 25, 2020 · 17 comments
Closed
13 tasks
Assignees
Labels
Feature: auto-case-distribution Priority: High Escalations from Support, blocking issue/NO workaround, or "first in" priority for new work. Product: caseflow-queue Stakeholder: BVA Functionality associated with the Board of Veterans' Appeals workflows/feature requests Team: Echo 🐬 Type: Enhancement Enhancement to an existing feature

Comments

@araposo-tistatech
Copy link

araposo-tistatech commented Jun 25, 2020

CHAIRMAN MASON PRIORITY TO BUILD A PRIORITY PUSH DISTRIBUTION. Requirements established/confirmed by Board POs

User or job story

User story: As a VLJ, I need priority cases (AOD & CAVC Remands) to be auto-distributed to me, so that I work these cases before legacy hearing & general population cases. These cases should also move to the top of my queue list.

Logic:
Auto-distribute priority cases evenly across judges, over the course of a month, authorized to receive auto-distributed cases (calculate # of cases for each judge by dividing total # priority cases / #judges authorized= priority target)

  • Auto-distribute priority cases that are tied to judges without a limit
  • Auto-distribute priority cases that are general population to each judge (each judge should get “priority target” number of cases). If the judge already reached or exceeded their “priority batch size” with cases that are tied to them in step a, skip to step b

Before cases are auto-distributed to VLJs a check will need to occur to ensure the VLJ is authorized to receive auto-distributed cases. Ticket to implement this feature #14608.

Acceptance criteria

  • This feature should be accessible to the following user groups: VLJs
  • A check occurs to ensure VLJ is authorized to receive auto-distributed cases (Create Front End for adding or removing VLJs from Auto-Distribution of Cases #14608)
  • VLJs that are authorized to receive auto-distributed cases receive priority cases tied to them as well as priority gen-pop cases
  • Gen-pop priority cases are distributed evenly among judges authorized to receive auto-distribution cases
  • VLJs receive priority cases tied to them without limit
  • Priority cases are listed on the top of the judges queue
  • Job runs weekly, day & time does not matter as there will no longer be a cap on cases assigned to a VLJ
  • Report containing the following is sent to slack at the end of the job
    • Number of priority cases distributed
    • Number of cases distributed waiting longer than 7 days
    • Number of cases not distributed
    • How to query cases not distributed
  • Update documentation: https://github.com/department-of-veterans-affairs/caseflow/wiki/Automatic-Case-Distribution

Release notes

Priority cases will now be auto-distributed to Veteran Law Judges on a {timeline} basis.

Technical notes

Priority cases will be removed from the "Request more cases" algorithm to ensure judges do not receive too many priority cases.

Notes from Alisa:
There is no maximum to how many priority cases a judge can receive, but we want to evenly spread them out amongst the judges as much as we can. We cannot evenly distribute cases that are tied to judges, so those have to go the judge they're tied to. I can see 2 ways of doing this

One possible way

  • 100 priority cases, 4 total judges
    In step A, let's say judge A has 10 priority cases tied to them, judge B has 20 priority cases tied to them, judge C has 30 and judge D has 0

Calculate priority target: 100 cases / 4 judges = 25 cases per judge

Step A

  • Judge A gets their 10 cases
  • Judge B gets their 20 cases
  • Judge C gets 30 cases
  • Judge D gets 0 cases
  • There are 40 more cases left to distribute that are not tied to any judges

Step B

  • Judge A gets 15 more cases to hit their priority target of 25 cases total
  • Judge B gets 5 cases since they already got 20, in order to hit priority target of 25
  • Judge C gets 0 since they already got 30, which is over the target
  • Judge D gets the remaining cases, which is just 20 cases left

Another way we can do this is separate out the priority cases tied to judges from the general population priority cases. And then base the priority target just on the general population cases. Not sure if the numbers would be more even this way or not

Other notes

Resources/other links

Product Brief: https://docs.google.com/document/d/1EjX-tYz0iI1hLP61p2p-O5rLvltj7NmlIofYRRwPMMs/edit#

@araposo-tistatech araposo-tistatech added Type: Enhancement Enhancement to an existing feature Product: caseflow-queue Team: Echo 🐬 Priority: Medium Blocking issue w/workaround, or "second in" priority for new work. labels Jun 25, 2020
@araposo-tistatech araposo-tistatech added Feature: auto-case-distribution Priority: High Escalations from Support, blocking issue/NO workaround, or "first in" priority for new work. Stakeholder: BVA Functionality associated with the Board of Veterans' Appeals workflows/feature requests and removed Priority: Medium Blocking issue w/workaround, or "second in" priority for new work. labels Jun 25, 2020
@hschallhorn
Copy link
Contributor

hschallhorn commented Jun 26, 2020

Some concerns:

  • Some judges will most likely have more cases linked to them than other judges. Should we try to make sure the distribution is as even as possible? Rather than splitting genpop across all judges, we could split them up so that all judges receive a similar amount
    Example:
    Judge A: 10 priority cases linked to them
    Judge B: 3 Priority cases linked to them
    Judge C: None
    15 Remaining genpop cases
    Distribute 6 to Judge B, 9 to judge C
    Judge A: 10
    Judge B: 9
    Judge C: 9
    Answered in ticket
  • Should this be behind a feature flag? I'm not sure how that would work. If we don't have a limit on the number of appeals to distribute, won't only the judges with the feature toggle receive alllllll the priority cases we have in case storage? (around 700 appeals)
  • Cases tied to a judge that is inactive or is an AVLJ should obviously not go to the judge or AVLJ. How do we want to handle these? Consider them genpop?
    Answered in estimation
  • Does this require updates to Distribution to indicated that this was auto distributed? To link distributions together?

@lomky
Copy link
Contributor

lomky commented Jun 26, 2020

what is this chart?

1 | 
2 | 
3 | 
5 | |||||
8 | |||||||

126 judges
~700 priority cases
Average of ~7 cases each, ignoring tied cases and judge team size

what do we do with cases tied to a no-longer authorized judges?

  • make gen pop priority?
  • No, legal requirement to process by the judge
    • vet has the right to waive them
  • Do we need a new task to block distribution, like 'we need to req a new hearing or waiver'
    • who gets this?
      • it sits in distribution
  • some way for us in eng to track this 'stuck' state
    • document the flow of letting hte board know
  • can we send these to the DVC?
    • no judge case to base this one
    • might interrupt their existing process

if there are fewer cases than judges, try to make it fair over a specified time period (round robin after the initial push)

  • note: our current round robin is a bit naive, assuming you can just pick up next user in the org. Myabe do something more robust here
  • how many runs?
  • remember who is one ahead, and prioritize evening that out, then plain round robin

Is this something we should split into multple issues?

  • it is big,m but how would we split it?
  • definitely stack/multiple PRs

Why 5?

  • New logic surrounding distributions. Will be updating the beautiful sql in vacols distribution
  • tests tests tests
  • assignment fairness considerations

Why 8?

  • 3 large reasons this is a 5 add up to an 8
  • uncertainty around lack of user research, questions open with the board

@lomky
Copy link
Contributor

lomky commented Jun 26, 2020

Feature Flag:

  • already hard to implement this logic
  • how can we consider the individual judges?

Alternative:
This is the last PR, no feature flag in this one.

Conclusion:

  • No feature flag for the auto-distribution job
  • Feature Flag on ACD will be turned off after this job is out and running
  • This code goes out when we want it to happen, and no sooner!

@hschallhorn
Copy link
Contributor

How can we quickly pull how many cases were pushed to each judge this month?

distributions_this_month = Distribution.completed.where(completed_at: Time.zone.now.beginning_of_month..Time.zone.now.end_of_month)
counts = distributions_this_month.pluck(:judge_id, :statistics).group_by(&:first).map { |judge_id, arr| [judge_id, arr.flat_map(&:last).map{ |stats| stats["batch_size"] }.reduce(:+)] }.to_h

# Quick sanity check
judge_id = 1491
distributions_ids = distributions_this_month.where(judge_id: judge_id).pluck(:id)
DistributedCase.where(distribution_id: distributions_ids).count == counts[judge_id]
=> true

How about the total distributed cases in the last month?

distributions_this_month = Distribution.completed.where(completed_at: Time.zone.now.beginning_of_month..Time.zone.now.end_of_month)
distributions_this_month.pluck(:statistics).map{ |stats| stats["batch_size"] }.reduce(:+) == DistributedCase.where(created_at: Time.zone.now.beginning_of_month..Time.zone.now.end_of_month).count
=> true

Hooowwwwww about the number of currently ready priority appeals?

docket_coordinator = DocketCoordinator.new
docket_coordinator.dockets.map { |docket| docket.last.count(priority: true, ready: true) }.reduce(&:+)
=> 1258

So our priority target for the whole month including this distribution will be

 (total_distributions_this_month + number_of_ready_priority_appeals) / elligable_judges.count

va-bot pushed a commit that referenced this issue Jul 14, 2020
Bumps #14604

### Description
Allows us to signify a distribution includes only priority cases pushed to a judge. Will allow us to filter by priority when calculating fairness for number of cases pushed to judges. Also allows us to skip some validations that we do not care about when pushing cases to judges.

### Acceptance Criteria
- [ ] Distributions can be created with a priority flag
- [ ] Validation for too_many_unassigned_cases is skipped when priority is true
- [ ] Validation for unassigned_cases_waiting_too_long is skipped when priority is true
- [ ] Validation for pending_distribution only checks for pending distributions of the same priority (a judge can have a pending distribution that they requested while still receiving a push priority case

### Database Changes
*Only for Schema Changes*

* [x] Column comments updated
* [x] Query profiling performed (eyeball Rails log, check bullet and fasterer output)
* [x] DB schema docs updated with `make docs`
* [x] #appeals-schema notified with summary and link to this PR
@hschallhorn
Copy link
Contributor

With this being a monthly goal, determining the real target is a little less straightforward. Consider the following

  • 5 judges
  • 100 cases distributed this month
  • 50 to distribute in this round
  • 30 priority target ((100 + 50) / 5) (referred to as "simple" in the table below)
Judge Distributions this month Simple priority target goal After simple distribution Ideal priority target goal After ideal distribution
A 50 0 50 0 50
B 25 5 30 0 25
C 25 5 30 0 25
D 0 30 30 25 25
E 0 10 (left of the 50 to distribute) 10 25 25

va-bot pushed a commit that referenced this issue Jul 17, 2020
Connects #14604 

### Description
JudgeTeam organizations have a new boolean field to note whether they are available for automatically pushed priority cases.

### Acceptance Criteria
- [ ] Test suite passes
- [ ] JudgeTeams availability are set to true for existing & new judge teams
- [ ] when queried via scope, only the available JudgeTeams are returned

### Testing Plan
1. Run the migration
   - [ ] Confirm all existing JudgeTeams have `true` set for `automated_priority_case_distribution`
   - [ ] Confirm all other org types are `nil`
2. On Console, query `JudgeTeam.available_for_priority_case_distribution`
   - [ ] Confirm all JudgeTeams are returned
3. On Console, update one JudgeTeam to be unavailable `JudgeTeam.first.update(automated_priority_case_distribution: false)
4. On Console, query `JudgeTeam.available_for_priority_case_distribution`
   - [ ] Confirm all JudgeTeams less the unavailable one are returned

### Database Changes
*Only for Schema Changes*

* [x] Column comments updated
* [x] DB schema docs updated with `make docs` (after running `make migrate`)
* [x] #appeals-schema notified with summary and link to this PR
@hschallhorn
Copy link
Contributor

hschallhorn commented Jul 20, 2020

With the addition of needing cases tied to users who were once AVLJs but may no longer be, the pool of users we pull for step one (Auto-distribute priority cases that are tied to judges without a limit) will be different from the users we pull in step two (Auto-distribute priority cases that are general population to each judge).

Current or previous AVLJs should get cases that are tied to them, but not any general population cases.

Let's look into how we would pull all cases tied to a vlj.

SELECT_PRIORITY_APPEALS_WITH_VLJ = "
  select SDOMAINID, COUNT(SDOMAINID)
    from (
      select SDOMAINID, case when BFHINES is null or BFHINES <> 'GP' then nvl(VLJ_HEARINGS.VLJ, VLJ_PRIORDEC.VLJ) end VLJ
      from (
        #{VACOLS::CaseDocket::SELECT_READY_APPEALS}
          and (BFAC = '7' or AOD = '1')
      ) BRIEFF
      #{VACOLS::CaseDocket::JOIN_ASSOCIATED_VLJS_BY_HEARINGS}
      #{VACOLS::CaseDocket::JOIN_ASSOCIATED_VLJS_BY_PRIOR_DECISIONS}
      inner join vacols.STAFF on STAFF.SATTYID = nvl(VLJ_HEARINGS.VLJ, VLJ_PRIORDEC.VLJ)
    )
  where SDOMAINID is not null
  group by SDOMAINID
  order by COUNT(SDOMAINID)
"

counts = VACOLS::CaseDocket.connection.exec_query(SELECT_PRIORITY_APPEALS_WITH_VLJ).rows.to_h
# => {"BVABCHATTER"=>1, "BVAPJOHNS"=>1, "BVASDALE"=>1, "BVACBOSELY"=>1, "BVAMDONOHUE"=>1, "BVAKZADORA"=>1, "BVABHENNINGS"=>1, "BVATHJONES"=>1, "BVATCATINO"=>1, "BVADCHIAPP"=>1, "BVARFEINBERG"=>1, "BVAASPECTOR"=>1, "BVACBRUCE"=>1, "BVABMULLINS"=>1, "BVAAPSIMPSON"=>1, "VACOHINDIM"=>1, "BVASPATEL"=>1, "BVAJPARKER"=>1, "BVAAISHIZ"=>1, "BVAMHERMAN"=>1, "BVAKOSBORNE"=>1, "BVAJMARKEY"=>1, "BVALBCRYAN"=>1, "BVAAJAEGER"=>1, "BVAMHAWLEY"=>1, "BVAMKILCOYN"=>1, "BVASKREMBS"=>1, "VACOLJBAKKE"=>2, "BVAMAUER"=>2, "BVAHSEESEL"=>2, "BVACTRUEBA"=>2, "BVAMCGRAHAM"=>2, "BVAAMADDOX"=>2, "BVADHACHEY"=>2, "BVALJENG"=>2, "BVAKGALAGHR"=>2, "BVAJFRANCIS"=>2, "BVAJZJONES"=>2, "BVAMSORISIO"=>2, "BVASDREISS"=>2, "VACOCARACA"=>2, "BVAJARNOLD"=>2, "BVATOSHAY"=>2, "BVACCRAWFOR"=>2, "VACOWHITEY"=>2, "BVAPSORISIO"=>3, "BVAKBANFIELD"=>3, "BVAURPOWELL"=>3, "BVAJCROWLEY"=>3, "BVAAMACKEN"=>3, "BVADWIGHT"=>3, "BVAWDONNELLY"=>3, "VACOBRAEUW"=>3, "BVAMBLACK"=>3, "BVAMAPAPPAS"=>3, "BVAJBKRAMER"=>3, "BVAPMLYNCH"=>3, "BVADBROWN"=>3, "BVAKBCONNER"=>3, "BVAHWALKER"=>3, "BVAGWASIK"=>4, "BVALHOWELL"=>4, "BVACASKOW"=>4, "BVAMHYLAND"=>4, "BVAVCHIAPP"=>4, "BVAKHADDOCK"=>4, "BVADJOHNSON"=>4, "BVALREIN"=>4, "BVAKALLEN"=>4, "VACOSTROMG"=>4, "BVAJHAGER"=>4, "BVACMASON"=>4, "BVAHSCHARTZ"=>4, "BVAJREINHART"=>4, "BVABBCOPELD"=>4, "BVAMDLYON"=>4, "BVAKGUNN"=>4, "BVASHENEKS"=>5, "BVASBUSH"=>5, "BVAAMAINELLI"=>5, "BVAKMILLIKAN"=>5, "VACODANNAT"=>5, "BVAJWILLS"=>5, "BVAGRSENYK"=>5, "BVAKPARAKAL"=>5, "BVAJHWA"=>5, "BVASBELCHER"=>5, "BVADWSINGLE"=>5, "BVAMLANE"=>5, "BVANKROES"=>5, "BVADBRENN"=>5, "BVANDOAN"=>5, "BVAEDEICHERT"=>6, "BVAMTENNER"=>6, "BVAKKORDICH"=>6, "BVAMLKANE"=>6, "BVARKESSEL"=>6, "BVAVELEZE"=>6, "BVABWILSON"=>7, "BVAKALIBRAN"=>7, "BVAMELARKIN"=>7, "BVAJMONROE"=>7, "BVASKENNEDY"=>7, "BVAVCLEMENT"=>7, "BVAHROBERT"=>7, "BVARSCHARNB"=>8, "BVATKONYA"=>8, "BVAVMOSHI"=>9, "BVAMJSKALT"=>10, "BVAMMARTIN"=>10, "BVAESLEBOFF"=>12, "BVALBARNARD"=>12}
# Max 12, min 1
# How many priority appeals are not tied to judges?
total_ready_priority = VACOLS::CaseDocket.counts_by_priority_and_readiness.detect { |h| h["priority"] == 1 && h["ready"] == 1 }["n"]
total_ready_priority - counts.values.sum
=> 299

@hschallhorn
Copy link
Contributor

#14745

@hschallhorn
Copy link
Contributor

job = PushPriorityAppealsToJudgesJob.new

# What judges are eligible for this?
job.eligible_judges.count
=> 99
JudgeTeam.active.count
=> 124
JudgeTeam.active.where(accepts_priority_pushed_cases: false).count
=> 25

# Let's check some of these calculations
job.priority_distributions_this_month
=> []
ready_priority_appeals_count = job.ready_priority_appeals_count
=> 1137

# How many appeals should be distributed to each judge ignoring cases tied to them?
job.priority_target
=> 11

# Let's look at cases tied to judges
priority_distributions_this_month_for_eligible_judges = job.eligible_judges.map do |judge|
  tied_count = VACOLS::CaseDocket.distribute_priority_appeals(judge, "not_genpop", 1000, dry_run: true).count
  [judge.id, tied_count]
end.to_h
priority_distributions_this_month_for_eligible_judges.sort_by(&:last).to_h
=> {1268=>0, 14783=>0, 14816=>0, 1611=>0, 1402=>0, 545=>0, 1032=>0, 753=>0, 1207=>0, 1491=>0, 817=>0, 1368=>0, 1409=>0, 1473=>0, 1217=>0, 845=>0, 1105=>1, 884=>1, 930=>1, 1590=>1, 1354=>1, 754=>1, 1160=>1, 719=>1, 992=>1, 1016=>1, 812=>1, 985=>1, 1335=>2, 1342=>2, 1431=>2, 889=>2, 1458=>2, 1554=>2, 1157=>2, 1060=>2, 1052=>2, 1193=>2, 826=>2, 1303=>2, 979=>2, 827=>2, 1612=>3, 819=>3, 1502=>3, 1346=>3, 755=>3, 1102=>3, 1137=>3, 1339=>3, 878=>4, 2168=>4, 1471=>4, 539=>4, 1495=>4, 1135=>4, 1279=>4, 1211=>5, 1047=>5, 1272=>5, 825=>5, 1353=>5, 1161=>6, 1426=>6, 1241=>6, 837=>6, 1290=>6, 1095=>7, 1144=>7, 944=>7, 1541=>7, 740=>7, 1470=>7, 1143=>7, 1423=>8, 1385=>8, 816=>8, 1546=>8, 1587=>9, 824=>9, 786=>9, 974=>9, 851=>9, 912=>9, 977=>10, 1094=>10, 1314=>10, 1494=>11, 728=>11, 1352=>11, 538=>12, 1381=>12, 972=>13, 1296=>14, 1048=>15, 1560=>15, 902=>16, 1215=>20, 1406=>21}

# Let's look at what our priority target would actually be then
distribution_counts = priority_distributions_this_month_for_eligible_judges.values
priority_target = (distribution_counts.sum + job.ready_priority_appeals_count) / distribution_counts.count

while distribution_counts.any? { |distribution_count| distribution_count > priority_target }
  distribution_counts = distribution_counts.reject { |distribution_count| distribution_count > priority_target }
  priority_target = (distribution_counts.sum + job.ready_priority_appeals_count) / distribution_counts.count
end
puts priority_target
=> 16

target_distributions_for_eligible_judges = priority_distributions_this_month_for_eligible_judges.map do |judge_id, distributions_this_month|
  target = priority_target - distributions_this_month
  (target >= 0) ? [judge_id, target] : nil
end.compact.to_h
=> {1268=>16, 14783=>16, 14816=>16, 1335=>14, 1211=>11, 1161=>10, 1587=>7, 538=>4, 1426=>10, 1105=>15, 824=>7, 1048=>1, 1611=>16, 1095=>9, 1144=>9, 1047=>11, 1612=>13, 902=>0, 878=>12, 786=>7, 944=>9, 884=>15, 930=>15, 2168=>12, 1471=>12, 1402=>16, 1494=>5, 1241=>10, 1541=>9, 539=>12, 1381=>4, 545=>16, 1342=>14, 1272=>11, 1590=>15, 1354=>15, 972=>3, 1032=>16, 1431=>14, 974=>7, 837=>10, 819=>13, 977=>6, 754=>15, 740=>9, 753=>16, 728=>5, 889=>14, 1207=>16, 1491=>16, 1352=>5, 851=>7, 1296=>2, 1458=>14, 1495=>12, 1502=>13, 1423=>8, 1560=>1, 1346=>13, 1385=>8, 755=>13, 817=>16, 1470=>9, 1554=>14, 1157=>14, 1060=>14, 1052=>14, 1160=>15, 1102=>13, 1193=>14, 912=>7, 1137=>13, 825=>11, 816=>8, 719=>15, 1094=>6, 1314=>6, 826=>14, 1290=>10, 1368=>16, 1409=>16, 992=>15, 1473=>16, 1303=>14, 1135=>12, 1279=>12, 1016=>15, 1217=>16, 812=>15, 1339=>13, 979=>14, 1353=>11, 1546=>8, 985=>15, 827=>14, 845=>16, 1143=>9}

leftover_cases_count = ready_priority_appeals_count - target_distributions_for_eligible_judges.values.sum
=> 27

leftover_cases = leftover_cases_count
eligible_judge_target_distributions_with_leftovers = target_distributions_for_eligible_judges.sort_by(&:last).map do |judge_id, target|
  if leftover_cases > 0
    leftover_cases -= 1
    target += 1
  end
  (target > 0) ? [judge_id, target] : nil
end.compact.to_h

eligible_judge_target_distributions_with_leftovers.sort_by(&:last).to_h
=> {902=>1, 1048=>2, 1560=>2, 1296=>3, 972=>4, 538=>5, 1381=>5, 1494=>6, 728=>6, 1352=>6, 977=>7, 1094=>7, 1314=>7, 1587=>8, 824=>8, 786=>8, 974=>8, 851=>8, 912=>8, 1423=>9, 1385=>9, 816=>9, 1546=>9, 740=>9, 1470=>9, 1143=>9, 1095=>10, 1144=>10, 944=>10, 1541=>10, 1161=>10, 1426=>10, 1241=>10, 837=>10, 1290=>10, 1211=>11, 1047=>11, 1272=>11, 825=>11, 1353=>11, 878=>12, 2168=>12, 1471=>12, 539=>12, 1495=>12, 1135=>12, 1279=>12, 1612=>13, 819=>13, 1502=>13, 1346=>13, 755=>13, 1102=>13, 1137=>13, 1339=>13, 1335=>14, 1342=>14, 1431=>14, 889=>14, 1458=>14, 1554=>14, 1157=>14, 1060=>14, 1052=>14, 1193=>14, 826=>14, 1303=>14, 979=>14, 827=>14, 1105=>15, 884=>15, 930=>15, 1590=>15, 1354=>15, 754=>15, 1160=>15, 719=>15, 992=>15, 1016=>15, 812=>15, 985=>15, 1268=>16, 14783=>16, 14816=>16, 1611=>16, 1402=>16, 545=>16, 1032=>16, 753=>16, 1207=>16, 1491=>16, 817=>16, 1368=>16, 1409=>16, 1473=>16, 1217=>16, 845=>16}

# Let's make sure any judge with tied cases would not get any genpop cases
judges_should_get_no_extra_cases = priority_distributions_this_month_for_eligible_judges.select { |_, count| count >= 16 }
judges_should_get_no_extra_cases.any? { |judge, _| eligible_judge_target_distributions_with_leftovers.values.include? judge }
=> false

# Let's make sure the calculated counts gets all other judges up to the priority target
eligible_judge_target_distributions_with_leftovers.map { |judge, count| count + priority_distributions_this_month_for_eligible_judges[judge] }.uniq
=> [17, 16]

Looks good!

@hschallhorn
Copy link
Contributor

hschallhorn commented Sep 24, 2020

Let's run a test run!

job = PushPriorityAppealsToJudgesJob.new

# What judges are eligible for this?
eligible_judges = job.eligible_judges
eligible_judges.count
=> 97

# How many cases are we distributing?
ready_priority_appeals_count = job.ready_priority_appeals_count
=> 1242

priority_distributions_this_month_for_eligible_judges = eligible_judges.map do |judge|
  tied_count = VACOLS::CaseDocket.distribute_priority_appeals(judge, "not_genpop", 1000, dry_run: true).count
  [judge.id, tied_count]
end.to_h
priority_distributions_this_month_for_eligible_judges.sort_by(&:last).to_h
=> {1268=>0, 14783=>0, 14816=>1, 1335=>2, 1161=>3, 1587=>11, 1215=>20, 538=>14, 1426=>1, 1105=>4, 824=>9, 1048=>16, 1611=>1, 1095=>10, 1144=>3, 1047=>4, 1612=>8, 902=>10, 878=>7, 786=>7, 944=>7, 884=>3, 930=>5, 2168=>7, 1471=>5, 1402=>7, 1494=>9, 1241=>5, 1541=>6, 539=>0, 1381=>15, 545=>1, 1342=>5, 1272=>4, 1590=>5, 1354=>2, 972=>2, 1032=>0, 1431=>2, 974=>8, 837=>3, 819=>0, 977=>8, 754=>4, 740=>6, 753=>8, 728=>12, 889=>7, 1207=>2, 1491=>3, 1352=>6, 851=>1, 1296=>16, 1458=>0, 1495=>6, 1502=>1, 1423=>0, 1560=>17, 1346=>3, 1385=>0, 1406=>8, 755=>2, 817=>0, 1554=>6, 1157=>2, 1060=>4, 1052=>3, 1160=>0, 1102=>2, 1193=>2, 912=>7, 1137=>6, 825=>7, 816=>8, 719=>4, 1094=>1, 1314=>12, 826=>3, 1290=>6, 1368=>2, 1409=>1, 992=>1, 1473=>0, 1303=>6, 1135=>4, 1279=>3, 1016=>1, 1217=>0, 812=>3, 1339=>2, 979=>6, 1353=>5, 1546=>6, 985=>1, 827=>3, 845=>3, 1143=>0}

# Let's look at what our priority target would actually be then
ready_priority_appeals_count = ready_priority_appeals_count - priority_distributions_this_month_for_eligible_judges.values.sum
=> 780
distribution_counts = priority_distributions_this_month_for_eligible_judges.values
priority_target = (distribution_counts.sum + ready_priority_appeals_count) / distribution_counts.count

while distribution_counts.any? { |distribution_count| distribution_count > priority_target }
  distribution_counts = distribution_counts.reject { |distribution_count| distribution_count > priority_target }
  priority_target = (distribution_counts.sum + ready_priority_appeals_count) / distribution_counts.count
end
priority_target
=> 12

target_distributions_for_eligible_judges = priority_distributions_this_month_for_eligible_judges.map do |judge_id, distributions_this_month|
  target = priority_target - distributions_this_month
  (target >= 0) ? [judge_id, target] : nil
end.compact.to_h

leftover_cases_count = ready_priority_appeals_count - target_distributions_for_eligible_judges.values.sum
=> 52

leftover_cases = leftover_cases_count
eligible_judge_target_distributions_with_leftovers = target_distributions_for_eligible_judges.sort_by(&:last).map do |judge_id, target|
  if leftover_cases > 0
    leftover_cases -= 1
    target += 1
  end
  (target > 0) ? [judge_id, target] : nil
end.compact.to_h

eligible_judge_target_distributions_with_leftovers.map { |judge, count| count + priority_distributions_this_month_for_eligible_judges[judge] }.uniq
=> [13, 12]

# Everything looks right. Let's run this. Safety first
job = PushPriorityAppealsToJudgesJob.new
ActiveRecord::Base.multi_transaction do
  job.perform_now
rescue => e
  Rails.logger.error(e.message)
  Rails.logger.error(e.backtrace.join("\n"))
end

Notes on watching everything fly by

  • Started at 2020-09-24 10:06:21
  • Looks like we're pulling all judge teams often. why is that?
  • On minute 20. Should look at making performance better here
  • All this runs at most twice for each judge. Will running this weekly cut down on run time as some judges will probably be receiving 0 cases as time goes on?
  • Should we remove the find here?
    judge: User.find(judge_id),
    Could simply pass around the judge or create the distribution with judge_id
  • Same:
    Distribution.create!(judge: User.find(judge.id), priority_push: true).tap(&:distribute!)
  • Also looks like a batch size of 0 does not cut down on the number of calls made to everything
  • End time: [2020-09-24 11:17:50 -0400] Hour and 10 minutes

DONE!!!!

PushPriorityAppealsToJudgesJob
[WARN]
Number of cases tied to judges distributed: 488
Number of general population cases distributed: 483
Age of oldest legacy case: 0 days
Age of oldest direct_review case: 0 days
Age of oldest evidence_submission case: 0 days
Age of oldest hearing case: 0 days
Number of appeals not distributed: 267
Debugging information
Priority Target: 12
Previous monthly distributions: {1268=>0, 14783=>0, 14816=>1, 1335=>2, 1161=>3, 1587=>13, 1215=>20, 538=>14, 1426=>1, 1105=>4, 824=>11, 1048=>19, 1611=>2, 1095=>10, 1144=>3, 1047=>4, 1612=>8, 902=>11, 878=>8, 786=>7, 944=>8, 884=>3, 930=>5, 2168=>8, 1471=>5, 1402=>7, 1494=>9, 1241=>5, 1541=>6, 539=>0, 1381=>15, 545=>1, 1342=>5, 1272=>4, 1590=>6, 1354=>2, 972=>2, 1032=>0, 1431=>3, 974=>8, 837=>3, 819=>0, 977=>8, 754=>4, 740=>6, 753=>8, 728=>12, 889=>7, 1207=>2, 1491=>3, 1352=>6, 851=>1, 1296=>16, 1458=>0, 1495=>6, 1502=>1, 1423=>0, 1560=>20, 1346=>3, 1385=>0, 1406=>9, 755=>2, 817=>0, 1554=>6, 1157=>2, 1060=>5, 1052=>3, 1160=>0, 1102=>2, 1193=>2, 912=>7, 1137=>6, 825=>7, 816=>10, 719=>4, 1094=>1, 1314=>12, 826=>5, 1290=>6, 1368=>2, 1409=>1, 992=>1, 1473=>0, 1303=>8, 1135=>4, 1279=>3, 1016=>2, 1217=>0, 812=>3, 1339=>2, 979=>6, 1353=>5, 1546=>6, 985=>1, 827=>3, 845=>3, 1143=>0}
Legacy appeals not distributed: LegacyAppeal.where(vacols_id: ["3988601", "3999344", "4009883", "4039613", "4050255", "4047128", "4052295", "4034462", "4052538", "4041550", "4053530", "4054216", "4054750", "4054595", "4052895", "4056281", "4056716", "4057398", "4052644", "4057302", "4043952", "4058185", "4054489", "4058178", "4052939", "4058465", "4052485", "4041759", "4058629", "4054211", "4059598", "4032359", "4059926", "4058247", "4060326", "4060197", "4058222", "4058232", "4060833", "4058346", "4060966", "4054651", "4053060", "4061807", "4061630", "4026450", "4053042", "4019554", "4062468", "4063016", "4042822", "4051356", "4063155", "4063129", "4048782", "4057108", "4063222", "4062341", "4043122", "4063631", "4063981", "4064130", "4062324", "4064134", "4053743", "4026165", "4062321", "4052083", "4065269", "4062586", "4054692", "4054897", "4065296", "4065395", "4066290", "4066535", "4066067", "4066342", "4067173", "4067014", "4067025", "4067923", "4067887", "4068226", "4068245", "4068400", "4068565", "4029444", "4054726", "4068805", "4068407", "4068799", "4052907", "4069383", "4069357", "4064605", "4069001", "4067051", "4067148", "4069946", "4052783", "4005121", "4066782", "4070295", "4068116", "4070694", "4070501", "4062178", "4070933", "4070959", "4071038", "4061028", "4071114", "4059307", "4071419", "4071369", "4066787", "4025722", "4070190", "4072262", "4072075", "4061856", "4072406", "4051176", "4065814", "4072924", "4072707", "4072712", "4072810", "4065112", "4055742", "4073057", "4011032", "4073082", "4058349", "3962126", "4073512", "4061638", "4069558", "4073394", "4072987", "4073339", "3362493", "4060842", "4074065", "4074085", "4074066", "4060289", "3993527", "4030610", "4039407", "4070775", "4066096", "4074450", "4071459", "4074606", "4074892", "4056753", "4071497", "4073197", "4074884", "4074675", "4074774", "4074886", "4074974", "4018580", "4047387", "4075345", "4075377", "4075108", "4075121", "4075367", "4075120", "4075374", "4075383", "4075229", "4069318", "4075439", "4075107", "4075617", "4067113", "4065686", "4067955", "4075487", "4055802", "4070069", "4075533", "4075765", "4075772", "4075942", "4062033", "4075861", "4075931", "4070157", "4006091", "4029179", "4048659", "4074578", "4074084", "4058575", "4076320", "4076342", "4069859", "4060042", "4076006", "4040402", "4074505", "4075919", "4076665", "4076356", "4076378", "4076617", "4073443", "4067432", "4074864", "4076506", "4076585", "4076636", "4076646", "4076661", "4076692", "4076695", "4073080", "4067757", "4076470", "4020232", "4076879", "4075334", "4073130", "4052616", "4076854", "4076855", "4076869", "4076880", "4076883", "4076890", "4076349", "4076751", "4056505", "4075003", "4074791", "4065919", "4076862", "4076873", "4068369"])
AMA appeals not distributed: Appeal.where(uuid: ["ab253469-8d94-402b-a1f8-3608271171ed", "caf1d7c3-ef65-4e4f-b26f-891e655cb548", "a5df5cd4-01b3-4d54-91c3-448711d62b0b", "6e49abef-2a0f-4394-b380-bbff7ae9ab2d", "b5ded8bf-f12f-4784-afc3-f0c1e1565531", "863f9833-2f7b-4e4a-a6b5-9f72e0d180a1", "4a4ce60b-f743-47a8-a563-72374f758cba", "b1f2b7ba-5b46-424d-8a4b-ef1399d2b7a3", "5cad2a9f-2828-4fae-af7d-12603f6c2203", "119c9456-3221-4df0-a375-d8616ccba1cc", "136209a9-ac8d-4ae4-ad15-cb24fea376f2", "b1ab176f-1866-4c21-a38b-94b0e236a2a8", "259a32e8-39cb-49f8-89f5-2cdeb439eebf", "2331fb61-688a-4259-9bb2-d27fa7de0866", "01f5e985-238e-484e-b503-7b77a253d2a6", "14b1a21f-3d0c-41d9-ae8a-a52bc6c9e1b8", "87965e92-b126-4658-a066-e7883a85a491", "fee976c9-5b29-4d6f-8e2d-81bca5becd87", "7e04db8b-caf2-457c-8a25-c88a933395b2", "f7d5d276-7dc6-4f55-9bd0-7f3f3322b960", "4ec794ff-7757-4496-bc62-040823328c4c", "2b9bcea4-66ec-4710-a358-e6c86e9754c1"])

@hschallhorn
Copy link
Contributor

hschallhorn commented Sep 24, 2020

Let's look into the cases that did not get distributed!

# Are our counts correct?
ready_priority_appeals_count = 1242
cases_distributed = 488 + 483
=> 971
DistributedCase.where(distribution: Distribution.where(priority_push: true)).count
=> 971
ready_priority_appeals_count - cases_distributed
=> 271
# Looks right

# Why weren't these legacy cases distributed?
vacols_ids = ["3988601", "3999344", "4009883", "4039613", "4050255", "4047128", "4052295", "4034462", "4052538", "4041550", "4053530", "4054216", "4054750", "4054595", "4052895", "4056281", "4056716", "4057398", "4052644", "4057302", "4043952", "4058185", "4054489", "4058178", "4052939", "4058465", "4052485", "4041759", "4058629", "4054211", "4059598", "4032359", "4059926", "4058247", "4060326", "4060197", "4058222", "4058232", "4060833", "4058346", "4060966", "4054651", "4053060", "4061807", "4061630", "4026450", "4053042", "4019554", "4062468", "4063016", "4042822", "4051356", "4063155", "4063129", "4048782", "4057108", "4063222", "4062341", "4043122", "4063631", "4063981", "4064130", "4062324", "4064134", "4053743", "4026165", "4062321", "4052083", "4065269", "4062586", "4054692", "4054897", "4065296", "4065395", "4066290", "4066535", "4066067", "4066342", "4067173", "4067014", "4067025", "4067923", "4067887", "4068226", "4068245", "4068400", "4068565", "4029444", "4054726", "4068805", "4068407", "4068799", "4052907", "4069383", "4069357", "4064605", "4069001", "4067051", "4067148", "4069946", "4052783", "4005121", "4066782", "4070295", "4068116", "4070694", "4070501", "4062178", "4070933", "4070959", "4071038", "4061028", "4071114", "4059307", "4071419", "4071369", "4066787", "4025722", "4070190", "4072262", "4072075", "4061856", "4072406", "4051176", "4065814", "4072924", "4072707", "4072712", "4072810", "4065112", "4055742", "4073057", "4011032", "4073082", "4058349", "3962126", "4073512", "4061638", "4069558", "4073394", "4072987", "4073339", "3362493", "4060842", "4074065", "4074085", "4074066", "4060289", "3993527", "4030610", "4039407", "4070775", "4066096", "4074450", "4071459", "4074606", "4074892", "4056753", "4071497", "4073197", "4074884", "4074675", "4074774", "4074886", "4074974", "4018580", "4047387", "4075345", "4075377", "4075108", "4075121", "4075367", "4075120", "4075374", "4075383", "4075229", "4069318", "4075439", "4075107", "4075617", "4067113", "4065686", "4067955", "4075487", "4055802", "4070069", "4075533", "4075765", "4075772", "4075942", "4062033", "4075861", "4075931", "4070157", "4006091", "4029179", "4048659", "4074578", "4074084", "4058575", "4076320", "4076342", "4069859", "4060042", "4076006", "4040402", "4074505", "4075919", "4076665", "4076356", "4076378", "4076617", "4073443", "4067432", "4074864", "4076506", "4076585", "4076636", "4076646", "4076661", "4076692", "4076695", "4073080", "4067757", "4076470", "4020232", "4076879", "4075334", "4073130", "4052616", "4076854", "4076855", "4076869", "4076880", "4076883", "4076890", "4076349", "4076751", "4056505", "4075003", "4074791", "4065919", "4076862", "4076873", "4068369"])
ready_legacy_appeals = VACOLS::CaseDocket.connection.exec_query(VACOLS::CaseDocket::SELECT_PRIORITY_APPEALS).to_hash
ready_legacy_appeals = ready_legacy_appeals.select { |appeal| vacols_ids.include? appeal["bfkey"] }
ready_legacy_appeals.any? { |appeal| appeal["vlj"].nil? }
=> false
# Age of oldest appeal is "correct". All cases tied to a judge, which age of oldest appeal does not take into account. Action Item to fix

# Why weren't these legacy cases distributed?
vlj_attyids_with_tied_ready_appeals = ready_legacy_appeals.map { |appeal| appeal["vlj"] }.uniq
vljs_with_tied_ready_appeals = vlj_attyids_with_tied_ready_appeals.map { |attyid| [attyid, User.find_by(css_id: VACOLS::Staff.find_by(sattyid: attyid).sdomainid)] }
attyids_with_no_caseflow_judge = vljs_with_tied_ready_appeals.select { |_, judge| judge.nil? }.map(&:first)
=> ["340", "413", "076", "141"]
# There are 4 judges in vacols with no caseflow user

vljs_with_caseflow_judge = vljs_with_tied_ready_appeals.reject { |_, judge| judge.nil? }
attyids_with_no_caseflow_judge_team = vljs_with_caseflow_judge.select { |_, judge| JudgeTeam.for_judge(judge).nil? }.map(&:first)
=> ["337", "588", "599", "1081", "1363", "1076", "815", "1020", "1440", "1152", "090", "592", "1446", "1145", "867", "1014", "569", "1498", "1109", "1313", "1359", "1100", "1436", "931", "1429", "1193", "1221", "1463", "992", "751", "963", "1133", "1191", "335", "1241", "382", "1129", "911", "962", "1304", "1192", "755", "821", "1073", "1301", "985", "1050", "1209", "1009", "575", "1340", "1269", "1298", "1559", "401", "1286", "1454", "1026", "390", "1402", "1337", "1353", "1237", "483", "863", "1423", "1034", "1028", "036", "429", "183"]
# There are 71 judges in vacols with tied cases with no judge team

vljs_with_caseflow_judge_team = vljs_with_caseflow_judge.reject { |_, judge| JudgeTeam.for_judge(judge).nil? }
attyids_with_no_active_caseflow_judge_team = vljs_with_caseflow_judge_team.select { |_, judge| JudgeTeam.for_judge(judge).inactive? }.map(&:first)
=> []
# No judges with an inactive team

attyids_with_caseflow_judge_team_job_toggled_off = vljs_with_caseflow_judge_team.reject { |_, judge| JudgeTeam.for_judge(judge).accepts_priority_pushed_cases? }.map(&:first)
=> ["679", "048", "894", "153", "418", "115", "1006", "801", "1155"]
# 9 judges that have this toggle disabled

vljs_with_caseflow_judge_team_can_accept_cases = vljs_with_caseflow_judge_team.select { |_, judge| JudgeTeam.for_judge(judge).accepts_priority_pushed_cases? }
vljs_with_caseflow_judge_team_can_accept_cases.count
=> 9

attyids_with_caseflow_judge_team_can_accept_cases = vljs_with_caseflow_judge_team_can_accept_cases.map(&:first)
cases_tied_to_valid_judge = ready_legacy_appeals.select { |appeal| attyids_with_caseflow_judge_team_can_accept_cases.include? appeal["vlj"] }
cases_tied_to_valid_judge.count
=> 11

# Why!
vacols_ids_of_cases_tied_to_valid_judges = cases_tied_to_valid_judge.map { |appeal| appeal["bfkey"] }
vacols_ids_of_cases_tied_to_valid_judges.count
=> 11
vacols_ids_of_cases_tied_to_valid_judges.map { |vacols_case| vacols_case["bfdloout"] }.uniq
=> [Thu, 24 Sep 2020]
legacy_appeals_tied_to_valid_judges = LegacyAppeal.where(vacols_id: vacols_ids_of_cases_tied_to_valid_judges)
legacy_appeals_tied_to_valid_judges.count
=> 1
# Does it matter that we do not have a legacy appeal for these vacols cases?

# Let's look into the one that does have a LegacyAppeal
legacy_appeal = legacy_appeals_tied_to_valid_judges.first
legacy_appeal.treee
                                 ┌────────────────────────────────────────────────────────────────────────────────┐
LegacyAppeal 1208758 (legacy) ──  ID      STATUS     ASGN_BY     ASGN_TO             UPDATED_AT              
├── RootTask                      907963  assigned               Bva                 2020-05-20 20:39:48 UTC 
└── ScheduleHearingColocatedTask  909629  completed  VACOODONNC  HearingsManagement  2020-06-24 18:36:45 UTC 
                                 └────────────────────────────────────────────────────────────────────────────────┘
# no open tasks, not an issue
# What judge is this case ties to?
tied_judge = User.find_by(css_id: VACOLS::Staff.find_by(sattyid: ready_legacy_appeals.detect { |appeal| appeal["bfkey"] == legacy_appeal.vacols_id }["vlj"]).sdomainid)
next_cases = VACOLS::CaseDocket.distribute_priority_appeals(tied_judge, "not_genpop", 10, dry_run: true)
=> [{"bfkey"=>"4020232", "bfdloout"=>2020-09-24 00:00:00 UTC, "vlj"=>"1060"}]
legacy_appeal.vacols_id
=> "4020232"
# Looks like this appeal would have been distributed next 🤔 

# What about for our other 10 cases?
cases_tied_to_valid_judge.all? do |vacols_case|
  tied_judge = User.find_by(css_id: VACOLS::Staff.find_by(sattyid: vacols_case["vlj"]).sdomainid)
  next_cases = VACOLS::CaseDocket.distribute_priority_appeals(tied_judge, "not_genpop", 10, dry_run: true)
  [vacols_case["bfkey"], next_cases.map { |next_case| next_case["bfkey"] }.include?(vacols_case["bfkey"])]
end
=> true

Legacy Appeals mid-conclusion

  • There are 234 appeals tied to judges that do not existing caseflow or do not have a judge team that accepts priority pushed cases
  • Still investigating the final 11 of these
ama_appeals =  Appeal.where(uuid: ["ab253469-8d94-402b-a1f8-3608271171ed", "caf1d7c3-ef65-4e4f-b26f-891e655cb548", "a5df5cd4-01b3-4d54-91c3-448711d62b0b", "6e49abef-2a0f-4394-b380-bbff7ae9ab2d", "b5ded8bf-f12f-4784-afc3-f0c1e1565531", "863f9833-2f7b-4e4a-a6b5-9f72e0d180a1", "4a4ce60b-f743-47a8-a563-72374f758cba", "b1f2b7ba-5b46-424d-8a4b-ef1399d2b7a3", "5cad2a9f-2828-4fae-af7d-12603f6c2203", "119c9456-3221-4df0-a375-d8616ccba1cc", "136209a9-ac8d-4ae4-ad15-cb24fea376f2", "b1ab176f-1866-4c21-a38b-94b0e236a2a8", "259a32e8-39cb-49f8-89f5-2cdeb439eebf", "2331fb61-688a-4259-9bb2-d27fa7de0866", "01f5e985-238e-484e-b503-7b77a253d2a6", "14b1a21f-3d0c-41d9-ae8a-a52bc6c9e1b8", "87965e92-b126-4658-a066-e7883a85a491", "fee976c9-5b29-4d6f-8e2d-81bca5becd87", "7e04db8b-caf2-457c-8a25-c88a933395b2", "f7d5d276-7dc6-4f55-9bd0-7f3f3322b960", "4ec794ff-7757-4496-bc62-040823328c4c", "2b9bcea4-66ec-4710-a358-e6c86e9754c1"])
ama_appeals.group(:docket_type).count
=> {"hearing"=>22}
ama_appeals.map(&:hearings).flatten.map(&:judge).any?(&:nil?)
=> false
# Age of oldest appeal is "correct". All cases tied to a judge, which age of oldest appeal does not take into account. Action Item to fix

tied_judges = ama_appeals.map(&:hearings).flatten.map(&:judge).uniq
tied_judges.count
=> 14

judge_css_ids_without_team = tied_judges.select { |judge| JudgeTeam.for_judge(judge).nil? }.map(&:css_id)
=> ["BVASKIM", "BVAJDEFRANK", "BVAMPRYCE", "BVAKBUCKLEY", "BVAJGALLAGHER", "BVAMSOBIECKI", "BVAASHAWKEY", "BVAJTHUTCHS", "BVAMCOLICELLI", "VACOHINDIM"]
judges_without_team.count
=> 10

judges_with_team = tied_judges.reject { |judge| JudgeTeam.for_judge(judge).nil? }
judge_css_ids_without_priority_push_team = judges_with_team.reject { |judge| JudgeTeam.for_judge(judge).accepts_priority_pushed_cases? }.map(&:css_id)
=> ["BVADBROWN", "BVAMPETERS", "BVAJREINHART", "BVAURPOWELL"]
judge_css_ids_without_priority_push_team.count
=> 4

Conclusion

  • Counts are correct!
  • 234 legacy appeals not distributed as they are tied to judges without a judge team in caseflow that accepts priority cases
  • 22 ama hearing appeals not distributed as they are tied to judges without a judge team in caseflow that accepts priority cases
  • Age of oldest DR docket ama appeal is 0 because there are none to distribute!
  • Age of oldest ES docket ama appeal is 0 because there are none to distribute!
  • 11 legacy appeals beacame available to be distributed as the job ran
  • Age of oldest legacy priority appeal is 0 because we only look at genpop legacy cases for this query
    def self.age_of_n_oldest_priority_appeals(num)
    conn = connection
    query = <<-SQL
    #{SELECT_PRIORITY_APPEALS}
    where VLJ is null and rownum <= ?
    SQL
    fmtd_query = sanitize_sql_array([query, num])
    appeals = conn.exec_query(fmtd_query).to_hash
    appeals.map { |appeal| appeal["bfdloout"] }
    end
  • Age of oldest hearing priority appeal is 0 because we only look at genpop legacy cases for this query
    def age_of_n_oldest_priority_appeals(num)
    relation = appeals(priority: true, ready: true).limit(num)
    HearingRequestDistributionQuery.new(
    base_relation: relation, genpop: "only_genpop"
    ).call.map(&:ready_for_distribution_at)
    end
  • Does it matter that we do not have a legacy appeal for these 10 vacols cases?
  • Will a vacols case without a legacy appeal still show in a judge's queue?

@hschallhorn
Copy link
Contributor

hschallhorn commented Sep 24, 2020

Let's find the actual age of the oldest ready appeals of non genpop cases

# Let's start with legacy
    query = <<-SQL
      #{VACOLS::CaseDocket::SELECT_PRIORITY_APPEALS}
      where rownum <= ?
    SQL

fmtd_query = VACOLS::CaseDocket.sanitize_sql_array([query, 1])
VACOLS::CaseDocket.connection.exec_query(fmtd_query).to_hash.first["bfdloout"]
=> 2019-10-07 00:00:00 UTC
(Time.zone.now.to_date - VACOLS::CaseDocket.connection.exec_query(fmtd_query).to_hash.first["bfdloout"].to_date).to_i
=> 353

# and ama hearing request?
ama_appeals =  Appeal.where(uuid: ["ab253469-8d94-402b-a1f8-3608271171ed", "caf1d7c3-ef65-4e4f-b26f-891e655cb548", "a5df5cd4-01b3-4d54-91c3-448711d62b0b", "6e49abef-2a0f-4394-b380-bbff7ae9ab2d", "b5ded8bf-f12f-4784-afc3-f0c1e1565531", "863f9833-2f7b-4e4a-a6b5-9f72e0d180a1", "4a4ce60b-f743-47a8-a563-72374f758cba", "b1f2b7ba-5b46-424d-8a4b-ef1399d2b7a3", "5cad2a9f-2828-4fae-af7d-12603f6c2203", "119c9456-3221-4df0-a375-d8616ccba1cc", "136209a9-ac8d-4ae4-ad15-cb24fea376f2", "b1ab176f-1866-4c21-a38b-94b0e236a2a8", "259a32e8-39cb-49f8-89f5-2cdeb439eebf", "2331fb61-688a-4259-9bb2-d27fa7de0866", "01f5e985-238e-484e-b503-7b77a253d2a6", "14b1a21f-3d0c-41d9-ae8a-a52bc6c9e1b8", "87965e92-b126-4658-a066-e7883a85a491", "fee976c9-5b29-4d6f-8e2d-81bca5becd87", "7e04db8b-caf2-457c-8a25-c88a933395b2", "f7d5d276-7dc6-4f55-9bd0-7f3f3322b960", "4ec794ff-7757-4496-bc62-040823328c4c", "2b9bcea4-66ec-4710-a358-e6c86e9754c1"])
ama_appeals.map(&:ready_for_distribution_at).sort.first
=> Mon, 04 May 2020 00:30:30 UTC +00:00
(Time.zone.now.to_date - ama_appeals.map(&:ready_for_distribution_at).sort.first.to_date).to_i
=> 143

Alert should have show:

Age of oldest legacy case: 353 days
Age of oldest direct_review case: 0 days
Age of oldest evidence_submission case: 0 days
Age of oldest hearing case: 143 days

@araposo-tistatech
Copy link
Author

@hschallhorn can we get a breakdown of how many of the cases distributed were CAVC and how many were AOD?

Also, we received the following questions from DVC S.:

  1. What does it mean that cases are tied to VLJs without teams? Who are those Judges? Retired? Acting?
    Yes, this can include VLJs in VACOLS that are not users in Caseflow, VLJs in VACOLS with tied cases with no judge team.
  2. With 971 cases distributed and about 100 VLJs I would expect most judges to get 10 or 11 cases but some got as many as 13 or 15. Do we know why?
  3. The report below says there were 22 AMA cases tied to VLJs that were not distributed? How can AMA cases be tied to VLJs?
  4. Can we get a report like this each week when the distribution is made?
    This request would be additional scope that would need to be prioritized.

If I knew the answer I've added it in italics. The others I was unsure of or are pertaining to pulling more data. Please let me know if you see anything that needs correction. Also, below is the report I had sent that is reference in question #4:

Total number of appeals awaiting distribution: 1242 (includes 4 cases ready for distribution after job completed running)
Total number of cases distributed: 971
Number of cases tied to judges distributed: 488
Number of general population cases distributed: 483
Total Number of appeals not distributed: 271
Legacy cases tied to VLJs without judge teams: 234
AMA cases tied to VLJs without judge teams: 22
Total Number of appeals still under investigation because they did not distribute properly: 11
Legacy cases: 11
AMA cases: 0
*****Caseflow will provide more details on the 11 cases above as soon as that information is available

@hschallhorn
Copy link
Contributor

@araposo-tistatech
2. Some judges have cases tied to them, some up to 20. These judges received all cases that are tied to them through hearings or previous decisions.
3. Ama hearings were held by these judges

@araposo-tistatech
Copy link
Author

@hschallhorn any update on this first request?

"can we get a breakdown of how many of the cases distributed were CAVC and how many were AOD?"

Can we get the same information for todays run?

@hschallhorn
Copy link
Contributor

hschallhorn commented Sep 28, 2020

Job just ran. Let's check in!

age of oldest waiting case will be off as #15313 has not yet been merged

Job ran in 50 minutes, down 20 from last time!

PushPriorityAppealsToJudgesJob
[WARN]
Number of cases tied to judges distributed: 133
Number of general population cases distributed: 60
Age of oldest legacy case: 0 days
Age of oldest direct_review case: 0 days
Age of oldest evidence_submission case: 0 days
Age of oldest hearing case: 0 days
Number of appeals not distributed: 296
Debugging information
Priority Target: 14
Previous monthly distributions: {1268=>1, 14783=>2, 14816=>1, 1335=>13, 1161=>14, 1587=>14, 1215=>23, 538=>18, 1426=>3, 1105=>13, 824=>16, 1048=>20, 1611=>12, 1095=>15, 1144=>17, 1047=>13, 1612=>15, 902=>15, 878=>14, 786=>16, 944=>13, 884=>16, 930=>14, 2168=>13, 1471=>15, 1402=>13, 1494=>13, 1241=>15, 1541=>13, 539=>5, 1381=>16, 545=>1, 1342=>17, 1272=>13, 1590=>14, 1354=>12, 972=>15, 1032=>2, 1431=>15, 974=>15, 837=>15, 819=>1, 977=>16, 754=>15, 740=>16, 753=>14, 728=>14, 889=>13, 1207=>12, 1491=>14, 1352=>15, 851=>4, 1296=>19, 1458=>1, 1495=>15, 1502=>1, 1423=>0, 1560=>22, 1346=>15, 1385=>2, 1406=>17, 755=>13, 817=>2, 1554=>13, 1157=>14, 1060=>15, 1052=>14, 1160=>1, 1102=>13, 1193=>14, 912=>13, 1137=>16, 825=>14, 816=>15, 719=>14, 1094=>1, 1314=>14, 826=>13, 1290=>16, 1368=>4, 1409=>3, 992=>2, 1473=>2, 1303=>14, 1135=>14, 1279=>13, 1016=>3, 1217=>0, 812=>15, 1339=>3, 979=>13, 1353=>16, 1546=>13, 985=>2, 827=>14, 845=>12, 1143=>0}
Legacy appeals not distributed: LegacyAppeal.where(vacols_id: ["3988601", "3999344", "4009883", "4046461", "4039613", "4050255", "4047128", "4052295", "4052538", "4034462", "4041550", "4054216", "4054750", "4054595", "4052895", "4056281", "4056716", "4057302", "4052644", "4057398", "4043952", "4041759", "4058178", "4058185", "4052485", "4058465", "4052939", "4054489", "4058629", "4054211", "4059598", "4032359", "4059926", "4058247", "4060197", "4060326", "4058222", "4058232", "4060833", "4060966", "4058346", "4054651", "4053060", "4061807", "4061630", "4026450", "4053042", "4019554", "4062468", "4042822", "4063016", "4051356", "4057108", "4048782", "4063155", "4063129", "4063222", "4062341", "4043122", "4063631", "4063981", "4064130", "4064134", "4062324", "4053743", "4062321", "4026165", "4065269", "4052083", "4054692", "4065296", "4062586", "4065395", "4054897", "4066535", "4066342", "4066067", "4066290", "4067025", "4067014", "4067173", "4067887", "4067923", "4068407", "4068565", "4068400", "4068245", "4068226", "4068799", "4054726", "4068805", "4029444", "4052907", "4064605", "4069357", "4069383", "4069001", "4005121", "4066782", "4067148", "4069946", "4052783", "4067051", "4070295", "4068116", "4070694", "4070501", "4071114", "4061028", "4071038", "4059307", "4070933", "4070959", "4062178", "4071369", "4071419", "4066787", "4025722", "4070190", "4072075", "4072262", "4051176", "4061856", "4072406", "4072924", "4065814", "4072810", "4072712", "4072707", "4065112", "4011032", "4073057", "4055742", "4073082", "3962126", "4072987", "4069558", "4073394", "4073512", "4058349", "4061638", "4073339", "3362493", "4060842", "4074065", "4074085", "4074066", "4060289", "3993527", "4030610", "4039407", "4070775", "4066096", "4074450", "4071459", "4074606", "4074892", "4056753", "4071497", "4073197", "4074884", "4074675", "4074774", "4074886", "4074974", "4018580", "4047387", "4075345", "4075377", "4075108", "4075121", "4075367", "4075120", "4075374", "4075383", "4075229", "4069318", "4075439", "4075107", "4075617", "4067113", "4065686", "4067955", "4075487", "4055802", "4070069", "4075533", "4075765", "4075772", "4075942", "4062033", "4075861", "4075931", "4070157", "4006091", "4029179", "4048659", "4074578", "4074084", "4058575", "4076320", "4076342", "4069859", "4060042", "4076006", "4040402", "4074505", "4075919", "4076665", "4076356", "4076378", "4076617", "4073443", "4067432", "4074864", "4076506", "4076585", "4076636", "4076646", "4076661", "4076692", "4076695", "4073080", "4067757", "4076470", "4048387", "4076985", "4062520", "4077037", "4075334", "4075803", "4073130", "4075463", "4076912", "4066464", "4052616", "4076880", "4076751", "4056505", "4077003", "4075003", "4074791", "4076239", "4076892", "4076959", "4068369", "4037764", "4077263", "4048521", "4075867", "4063930", "4075635", "4073651", "4077231", "4077245", "4055516", "4077117", "4077156", "4077171", "4077180", "4076158", "4077101", "4058449", "4077166", "4077170", "4029534", "4077334", "4077338", "4077328", "4077339", "4076381", "4077336", "4077337", "4077333"])
AMA appeals not distributed: Appeal.where(uuid: ["ab253469-8d94-402b-a1f8-3608271171ed", "caf1d7c3-ef65-4e4f-b26f-891e655cb548", "a5df5cd4-01b3-4d54-91c3-448711d62b0b", "6e49abef-2a0f-4394-b380-bbff7ae9ab2d", "b5ded8bf-f12f-4784-afc3-f0c1e1565531", "863f9833-2f7b-4e4a-a6b5-9f72e0d180a1", "4a4ce60b-f743-47a8-a563-72374f758cba", "b1f2b7ba-5b46-424d-8a4b-ef1399d2b7a3", "5cad2a9f-2828-4fae-af7d-12603f6c2203", "119c9456-3221-4df0-a375-d8616ccba1cc", "136209a9-ac8d-4ae4-ad15-cb24fea376f2", "b1ab176f-1866-4c21-a38b-94b0e236a2a8", "259a32e8-39cb-49f8-89f5-2cdeb439eebf", "2331fb61-688a-4259-9bb2-d27fa7de0866", "01f5e985-238e-484e-b503-7b77a253d2a6", "14b1a21f-3d0c-41d9-ae8a-a52bc6c9e1b8", "87965e92-b126-4658-a066-e7883a85a491", "fee976c9-5b29-4d6f-8e2d-81bca5becd87", "7e04db8b-caf2-457c-8a25-c88a933395b2", "f7d5d276-7dc6-4f55-9bd0-7f3f3322b960", "4ec794ff-7757-4496-bc62-040823328c4c", "2b9bcea4-66ec-4710-a358-e6c86e9754c1"])

Legacy Appeals

vacols_ids = ["3988601", "3999344", "4009883", "4046461", "4039613", "4050255", "4047128", "4052295", "4052538", "4034462", "4041550", "4054216", "4054750", "4054595", "4052895", "4056281", "4056716", "4057302", "4052644", "4057398", "4043952", "4041759", "4058178", "4058185", "4052485", "4058465", "4052939", "4054489", "4058629", "4054211", "4059598", "4032359", "4059926", "4058247", "4060197", "4060326", "4058222", "4058232", "4060833", "4060966", "4058346", "4054651", "4053060", "4061807", "4061630", "4026450", "4053042", "4019554", "4062468", "4042822", "4063016", "4051356", "4057108", "4048782", "4063155", "4063129", "4063222", "4062341", "4043122", "4063631", "4063981", "4064130", "4064134", "4062324", "4053743", "4062321", "4026165", "4065269", "4052083", "4054692", "4065296", "4062586", "4065395", "4054897", "4066535", "4066342", "4066067", "4066290", "4067025", "4067014", "4067173", "4067887", "4067923", "4068407", "4068565", "4068400", "4068245", "4068226", "4068799", "4054726", "4068805", "4029444", "4052907", "4064605", "4069357", "4069383", "4069001", "4005121", "4066782", "4067148", "4069946", "4052783", "4067051", "4070295", "4068116", "4070694", "4070501", "4071114", "4061028", "4071038", "4059307", "4070933", "4070959", "4062178", "4071369", "4071419", "4066787", "4025722", "4070190", "4072075", "4072262", "4051176", "4061856", "4072406", "4072924", "4065814", "4072810", "4072712", "4072707", "4065112", "4011032", "4073057", "4055742", "4073082", "3962126", "4072987", "4069558", "4073394", "4073512", "4058349", "4061638", "4073339", "3362493", "4060842", "4074065", "4074085", "4074066", "4060289", "3993527", "4030610", "4039407", "4070775", "4066096", "4074450", "4071459", "4074606", "4074892", "4056753", "4071497", "4073197", "4074884", "4074675", "4074774", "4074886", "4074974", "4018580", "4047387", "4075345", "4075377", "4075108", "4075121", "4075367", "4075120", "4075374", "4075383", "4075229", "4069318", "4075439", "4075107", "4075617", "4067113", "4065686", "4067955", "4075487", "4055802", "4070069", "4075533", "4075765", "4075772", "4075942", "4062033", "4075861", "4075931", "4070157", "4006091", "4029179", "4048659", "4074578", "4074084", "4058575", "4076320", "4076342", "4069859", "4060042", "4076006", "4040402", "4074505", "4075919", "4076665", "4076356", "4076378", "4076617", "4073443", "4067432", "4074864", "4076506", "4076585", "4076636", "4076646", "4076661", "4076692", "4076695", "4073080", "4067757", "4076470", "4048387", "4076985", "4062520", "4077037", "4075334", "4075803", "4073130", "4075463", "4076912", "4066464", "4052616", "4076880", "4076751", "4056505", "4077003", "4075003", "4074791", "4076239", "4076892", "4076959", "4068369", "4037764", "4077263", "4048521", "4075867", "4063930", "4075635", "4073651", "4077231", "4077245", "4055516", "4077117", "4077156", "4077171", "4077180", "4076158", "4077101", "4058449", "4077166", "4077170", "4029534", "4077334", "4077338", "4077328", "4077339", "4076381", "4077336", "4077337", "4077333"]
ready_legacy_appeals = VACOLS::CaseDocket.connection.exec_query(VACOLS::CaseDocket::SELECT_PRIORITY_APPEALS).to_hash
ready_legacy_appeals = ready_legacy_appeals.select { |appeal| vacols_ids.include? appeal["bfkey"] }

# Are these all tied to judges?
cases_not_tied_to_a_judge = ready_legacy_appeals.select { |appeal| appeal["vlj"].nil? }
cases_not_tied_to_a_judge.count
=> 29
# 29 cases not tied to a judge

# Do all that are tied to judges have a judge team that accepts priority pushed cases?
vlj_attyids_with_tied_ready_appeals = ready_legacy_appeals.map { |appeal| appeal["vlj"] }.uniq
vljs_with_tied_ready_appeals = vlj_attyids_with_tied_ready_appeals.map { |attyid| [attyid, User.find_by(css_id: VACOLS::Staff.find_by(sattyid: attyid).sdomainid)] }
attyids_with_no_caseflow_judge = vljs_with_tied_ready_appeals.select { |_, judge| judge.nil? }.map(&:first).compact
=> ["340"]
# One judge not in caseflow

vljs_with_caseflow_judge = vljs_with_tied_ready_appeals.reject { |_, judge| judge.nil? }
attyids_with_no_caseflow_judge_team = vljs_with_caseflow_judge.select { |_, judge| JudgeTeam.for_judge(judge).nil? }.map(&:first)
=> ["337", "588", "599", "1081", "1363", "1076", "815", "1020", "1440", "1446", "090", "592", "1152", "1145", "867", "569", "1498", "1014", "1313", "1109", "1100", "1359", "1436", "931", "1193", "1429", "1221", "1463", "992", "751", "963", "1133", "1191", "335", "1241", "382", "1129", "911", "1304", "1192", "962", "755", "821", "1301", "1073", "985", "1050", "1209", "1009", "575", "1340", "1559", "1269", "1298", "401", "1286", "1454", "390", "1026", "1402", "1353", "1237", "1337", "483", "863", "1423", "1034", "1177", "1568"]
# There are 69 judges in vacols with tied cases with no judge team

vljs_with_caseflow_judge_team = vljs_with_caseflow_judge.reject { |_, judge| JudgeTeam.for_judge(judge).nil? }
attyids_with_no_active_caseflow_judge_team = vljs_with_caseflow_judge_team.select { |_, judge| JudgeTeam.for_judge(judge).inactive? }.map(&:first)
=> []
# No judges with an inactive team

attyids_with_caseflow_judge_team_job_toggled_off = vljs_with_caseflow_judge_team.reject { |_, judge| JudgeTeam.for_judge(judge).accepts_priority_pushed_cases? }.map(&:first)
=> ["679", "048", "894", "418", "115", "1006", "801", "1155", "986", "1022"]
# 10 judges that have this toggle disabled

vljs_with_caseflow_judge_team_can_accept_cases = vljs_with_caseflow_judge_team.select { |_, judge| JudgeTeam.for_judge(judge).accepts_priority_pushed_cases? }
vljs_with_caseflow_judge_team_can_accept_cases.count
=> 7

attyids_with_caseflow_judge_team_can_accept_cases = vljs_with_caseflow_judge_team_can_accept_cases.map(&:first)
cases_tied_to_valid_judge = ready_legacy_appeals.select { |appeal| attyids_with_caseflow_judge_team_can_accept_cases.include? appeal["vlj"] }
cases_tied_to_valid_judge.count
=> 8
cases_tied_to_valid_judge.map { |vacols_case| vacols_case["bfdloout"] }.uniq
=> [2020-09-28 00:00:00 UTC]

# Will these cases be distributed next time around?
cases_tied_to_valid_judge.all? do |vacols_case|
  tied_judge = User.find_by(css_id: VACOLS::Staff.find_by(sattyid: vacols_case["vlj"]).sdomainid)
  next_cases = VACOLS::CaseDocket.distribute_priority_appeals(tied_judge, "not_genpop", 10, dry_run: true)
  [vacols_case["bfkey"], next_cases.map { |next_case| next_case["bfkey"] }.include?(vacols_case["bfkey"])]
end
=> true

(Time.zone.now.to_date - ready_legacy_appeals.min_by { |appeal| appeal["bfdloout"] }["bfdloout"].to_date).to_i
=> 357

AMA Appeals

ama_appeals = Appeal.where(uuid: ["ab253469-8d94-402b-a1f8-3608271171ed", "caf1d7c3-ef65-4e4f-b26f-891e655cb548", "a5df5cd4-01b3-4d54-91c3-448711d62b0b", "6e49abef-2a0f-4394-b380-bbff7ae9ab2d", "b5ded8bf-f12f-4784-afc3-f0c1e1565531", "863f9833-2f7b-4e4a-a6b5-9f72e0d180a1", "4a4ce60b-f743-47a8-a563-72374f758cba", "b1f2b7ba-5b46-424d-8a4b-ef1399d2b7a3", "5cad2a9f-2828-4fae-af7d-12603f6c2203", "119c9456-3221-4df0-a375-d8616ccba1cc", "136209a9-ac8d-4ae4-ad15-cb24fea376f2", "b1ab176f-1866-4c21-a38b-94b0e236a2a8", "259a32e8-39cb-49f8-89f5-2cdeb439eebf", "2331fb61-688a-4259-9bb2-d27fa7de0866", "01f5e985-238e-484e-b503-7b77a253d2a6", "14b1a21f-3d0c-41d9-ae8a-a52bc6c9e1b8", "87965e92-b126-4658-a066-e7883a85a491", "fee976c9-5b29-4d6f-8e2d-81bca5becd87", "7e04db8b-caf2-457c-8a25-c88a933395b2", "f7d5d276-7dc6-4f55-9bd0-7f3f3322b960", "4ec794ff-7757-4496-bc62-040823328c4c", "2b9bcea4-66ec-4710-a358-e6c86e9754c1"])
ama_appeals.group(:docket_type).count
=> {"hearing"=>22}
ama_appeals.map(&:hearings).flatten.map(&:judge).any?(&:nil?)
=> false

tied_judges = ama_appeals.map(&:hearings).flatten.map(&:judge).uniq
tied_judges.count
=> 14

judge_css_ids_without_team = tied_judges.select { |judge| JudgeTeam.for_judge(judge).nil? }.map(&:css_id)
=> ["BVASKIM", "BVAJDEFRANK", "BVAMPRYCE", "BVAKBUCKLEY", "BVAJGALLAGHER", "BVAMSOBIECKI", "BVAASHAWKEY", "BVAJTHUTCHS", "BVAMCOLICELLI", "VACOHINDIM"]
judge_css_ids_without_team.count
=> 10

judges_with_team = tied_judges.reject { |judge| JudgeTeam.for_judge(judge).nil? }
judge_css_ids_without_priority_push_team = judges_with_team.reject { |judge| JudgeTeam.for_judge(judge).accepts_priority_pushed_cases? }.map(&:css_id)
=> ["BVADBROWN", "BVAMPETERS", "BVAJREINHART", "BVAURPOWELL"]
judge_css_ids_without_priority_push_team.count
=> 4

(Time.zone.now.to_date - ama_appeals.map(&:ready_for_distribution_at).sort.first.to_date).to_i
=> 147

Conclusion

  • 29 legacy cases not tied to a judge that were not distributed but will be the next time the job is run
  • 8 cases tied to judges that can receive priority pushed cases that became ready to distribute while job was running and will be distributed in the next push job
  • Still the same 22 ama cases that did not get distributed as they are not tied to a judge that has a judge team that accepts priority cases
  • Age of oldest hearing legacy case: 357
  • Age of oldest hearing case: 147
  • Age of oldest all other dockets correct

@hschallhorn
Copy link
Contributor

can we get a breakdown of how many of the cases distributed were CAVC and how many were AOD?

first_distributions = Distribution.priority_pushed.where("created_at < ?", 1.day.ago)
first_distributions.count
=> 187

distributed_cases = first_distributions.flat_map(&:distributed_cases)
distributed_cases.count
=> 971
distributed_cases.select { |distributed_case| distributed_case.docket == "legacy" ?  LegacyAppeal.find_by(vacols_id: distributed_case.case_id).aod? : Appeal.find_by(uuid: distributed_case.case_id).aod? }.count
=> 526
distributed_cases.select { |distributed_case| distributed_case.docket == "legacy" &&  LegacyAppeal.find_by(vacols_id: distributed_case.case_id).cavc? }.count
=> 499
# 526 + 499 > 971 because cases can be aod and cavc


second_distributions = Distribution.priority_pushed.where("created_at > ?", 1.day.ago)
second_distributions.count
=> 161
distributed_cases = second_distributions.flat_map(&:distributed_cases)
distributed_cases.count
=> 193

# Looks like a few of these don't yet have appeals
no_appeal_vacols_ids = distributed_cases.select { |distributed_case| distributed_case.docket == "legacy" &&  LegacyAppeal.find_by(vacols_id: distributed_case.case_id).nil? }.map(&:case_id)
no_appeal_vacols_ids.each { |vacols_id| LegacyAppeal.find_or_create_by_vacols_id(vacols_id) }

distributed_cases.select { |distributed_case| distributed_case.docket == "legacy" ?  LegacyAppeal.find_by(vacols_id: distributed_case.case_id).aod? : Appeal.find_by(uuid: distributed_case.case_id).aod? }.count
=> 153
distributed_cases.select { |distributed_case| distributed_case.docket == "legacy" &&  LegacyAppeal.find_by(vacols_id: distributed_case.case_id).cavc? }.count
=> 43
# 153 + 48 > 193 because cases can be aod and cavc

Conclusion

Thursday job:

  • 526 aod
  • 499 cvac

Today's job

  • 153 aod
  • 43 cavc

@hschallhorn
Copy link
Contributor

hschallhorn commented Sep 28, 2020

Why were there 29 cases not tied to a judge that did not distribute?

vacols_ids = ["3988601", "3999344", "4009883", "4046461", "4039613", "4050255", "4047128", "4052295", "4052538", "4034462", "4041550", "4054216", "4054750", "4054595", "4052895", "4056281", "4056716", "4057302", "4052644", "4057398", "4043952", "4041759", "4058178", "4058185", "4052485", "4058465", "4052939", "4054489", "4058629", "4054211", "4059598", "4032359", "4059926", "4058247", "4060197", "4060326", "4058222", "4058232", "4060833", "4060966", "4058346", "4054651", "4053060", "4061807", "4061630", "4026450", "4053042", "4019554", "4062468", "4042822", "4063016", "4051356", "4057108", "4048782", "4063155", "4063129", "4063222", "4062341", "4043122", "4063631", "4063981", "4064130", "4064134", "4062324", "4053743", "4062321", "4026165", "4065269", "4052083", "4054692", "4065296", "4062586", "4065395", "4054897", "4066535", "4066342", "4066067", "4066290", "4067025", "4067014", "4067173", "4067887", "4067923", "4068407", "4068565", "4068400", "4068245", "4068226", "4068799", "4054726", "4068805", "4029444", "4052907", "4064605", "4069357", "4069383", "4069001", "4005121", "4066782", "4067148", "4069946", "4052783", "4067051", "4070295", "4068116", "4070694", "4070501", "4071114", "4061028", "4071038", "4059307", "4070933", "4070959", "4062178", "4071369", "4071419", "4066787", "4025722", "4070190", "4072075", "4072262", "4051176", "4061856", "4072406", "4072924", "4065814", "4072810", "4072712", "4072707", "4065112", "4011032", "4073057", "4055742", "4073082", "3962126", "4072987", "4069558", "4073394", "4073512", "4058349", "4061638", "4073339", "3362493", "4060842", "4074065", "4074085", "4074066", "4060289", "3993527", "4030610", "4039407", "4070775", "4066096", "4074450", "4071459", "4074606", "4074892", "4056753", "4071497", "4073197", "4074884", "4074675", "4074774", "4074886", "4074974", "4018580", "4047387", "4075345", "4075377", "4075108", "4075121", "4075367", "4075120", "4075374", "4075383", "4075229", "4069318", "4075439", "4075107", "4075617", "4067113", "4065686", "4067955", "4075487", "4055802", "4070069", "4075533", "4075765", "4075772", "4075942", "4062033", "4075861", "4075931", "4070157", "4006091", "4029179", "4048659", "4074578", "4074084", "4058575", "4076320", "4076342", "4069859", "4060042", "4076006", "4040402", "4074505", "4075919", "4076665", "4076356", "4076378", "4076617", "4073443", "4067432", "4074864", "4076506", "4076585", "4076636", "4076646", "4076661", "4076692", "4076695", "4073080", "4067757", "4076470", "4048387", "4076985", "4062520", "4077037", "4075334", "4075803", "4073130", "4075463", "4076912", "4066464", "4052616", "4076880", "4076751", "4056505", "4077003", "4075003", "4074791", "4076239", "4076892", "4076959", "4068369", "4037764", "4077263", "4048521", "4075867", "4063930", "4075635", "4073651", "4077231", "4077245", "4055516", "4077117", "4077156", "4077171", "4077180", "4076158", "4077101", "4058449", "4077166", "4077170", "4029534", "4077334", "4077338", "4077328", "4077339", "4076381", "4077336", "4077337", "4077333"]
ready_legacy_appeals = VACOLS::CaseDocket.connection.exec_query(VACOLS::CaseDocket::SELECT_PRIORITY_APPEALS).to_hash
ready_legacy_appeals = ready_legacy_appeals.select { |appeal| vacols_ids.include? appeal["bfkey"] }

# Let's find all the cases that are not tied to a judge
cases_not_tied_to_a_judge = ready_legacy_appeals.select { |appeal| appeal["vlj"].nil? }
cases_not_tied_to_a_judge.count
=> 28

# Let's filter out any that were not ready to be distributed before today
cases_not_tied_to_a_judge = cases_not_tied_to_a_judge.reject { |appeal| appeal["bfdloout"] > 1.day.ago.to_date } 
cases_not_tied_to_a_judge.count
=> 28
# dang

# Let's see if these will distribute next time a distribution is run.
undistributed_vacols_ids = cases_not_tied_to_a_judge.map { |appeal| appeal["bfkey"] }
=> ["4058349", "3962126", "4030610", "4056753", "4018580", "4065686", "4067955", "4062033", "4069859", "4048659", "4074578", "4076665", "4076646", "4076692", "4076695", "4067757", "4074505", "4075334", "4073130", "4075463", "4075003", "4074791", "4076239", "4048521", "4063930", "4055516", "4076158", "4077101"]

tied_judge = User.find_by(css_id: VACOLS::Staff.find_by(sattyid: "679").sdomainid)
next_cases = VACOLS::CaseDocket.distribute_priority_appeals(tied_judge, "only_genpop", 50, dry_run: true)
next_cases_vacols_ids = next_cases.map { |next_case| next_case["bfkey"] }
case_ids_wont_distribute = undistributed_vacols_ids.reject { |vacols_id| next_cases_vacols_ids.include? vacols_id }
=> []
# These will all be distributed next time around

va-bot pushed a commit that referenced this issue Sep 29, 2020
…pop cases (#15313)

Resolves issue found [here](#14604 (comment))

### Description
age_of_n_oldest_priority_appeals only queries genpop appeals, so for legacy and hearing cases, it does not consider older appeals that are tied to a judge. This PR renames this function to be specific to genpop appeals. This PR also creates a new function to determine the age of the oldest appeal on any docket, regardless of whether or not it is tied to a judge. This function is now used to report the oldest case in `PushPriorityAppealsToJudgesJob.slack_report`.

### Acceptance Criteria
- [x] `age_of_n_oldest_priority_appeals` -> `age_of_n_oldest_genpop_priority_appeals` everywhere in the code
- [ ] `docket.oldest_priority_appeal_days_waiting` reports the age of the oldest case, even if that case is tied to a judge

### Testing
1. In prod
```ruby
# Old method
HearingRequestDocket.new.oldest_priority_appeal_days_waiting
=> 0
LegacyDocket.new.oldest_priority_appeal_days_waiting
=> 0

# New methods
HearingRequestDocket.new.appeals(priority: true, ready: true).limit(1).first.ready_for_distribution_at
=> Mon, 04 May 2020 00:30:30 UTC +00:00
conn = VACOLS::CaseDocket.connection
query = <<-SQL
      #{VACOLS::CaseDocket::SELECT_PRIORITY_APPEALS}
      where rownum <= ?
    SQL
fmtd_query = VACOLS::CaseDocket.sanitize_sql_array([query, 1])
conn.exec_query(fmtd_query).to_hash.first["bfdloout"]
=> 2019-10-07 00:00:00 UTC
```
@jessalvesdesa jessalvesdesa changed the title Create Auto-Distribution Job for Priority Cases Chairman Mason Priority: Create Auto-Distribution Job for Priority Cases Oct 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature: auto-case-distribution Priority: High Escalations from Support, blocking issue/NO workaround, or "first in" priority for new work. Product: caseflow-queue Stakeholder: BVA Functionality associated with the Board of Veterans' Appeals workflows/feature requests Team: Echo 🐬 Type: Enhancement Enhancement to an existing feature
Projects
None yet
Development

No branches or pull requests

3 participants