We currently use Tasks to describe responsibility for completing the various actions it takes to process an appeal through the Board. This is proving to be a good model for meeting that objective, but less than ideal at the job of describing when they were taken and precisely what those actions were. I propose we adopt an additional model whose explicit purpose is tracking activity that has happened on tasks assigned to an appeal.
The proposed model (tentatively dubbed TaskEvents) aspires to improve on three weaknesses with the pure Task model:
create table task_events (
id serial,
task_id integer,
time timestamp,
description text
);
One pattern our co-located pilots are employing is placing short term holds on tasks when waiting for email responses, adding a note explaining why the task is on hold when they do so. Currently, this appends the note to the Task's instructions field without any information about when the note was made or who made the note. By storing these notes as TaskEvents, we would know when they happened and could infer who created them by looking at who the task was assigned to (or we could add a created_by column to TaskEvent). This would also remove the confusion caused by us overloading the instructions column to include assigner instructions and assignee notes.
Currently there is no way for a Task's assignee to include a message to the assigner when the assignee completes the Task. We could offer the assignee the option to add a note (as a TaskEvent) to the Task they are completing. We could then display that in the Case Timeline and rely on the assigner looking in the Case Timeline for that information, or we could pluck the final TaskEvent off of the parent Task's child Task and show it in the Case Snapshot.
If a co-located staffer creates a hold for Task that was previously put on hold we overwrite the previous on hold information. I suspect this on hold information may be important when trying to understand the timeline of an appeal if it took an extraordinarily long time to process (say there are three extension requests granted we will only record one in the Task table).
The TaskEvent model described above results in a linear timeline of events that happened on to an appeal's Tasks. As such it might provide a handy shortcut for constructing the timeline of events on an appeal if we created a TaskEvent for each event that happened on an appeal, to include RootTask creation, assignment to attorney, new mail received at the Board, and so on. We could add a category column to the table to distinguish between more salient events like task creation, holds, and notes.
See also: Turning the Database Inside Out
@evankroske The TaskEvent model described above is precisely an append-only event log. In the near future the TaskEvent approach would only be adding roughly 10 million rows every year (with generous upper bounds of 100,000 appeals/year x 100 tasks/appeal if we put all events attached to an appeal in the log) which postgres could easily handle for a few years (though we will be doing lookups based on appeal so we would be wise to add an indexed appeal_id column) before transitioning over to a real event log/stream or bigtable/columnar data store system just so we don't have to deal with the overhead of adding that tool right now while we're still in proof of concept phase.
Some thoughts here.
1) Diary concerns me. From what I can tell VACOLS diaries became a place to store tons of different types of data. Maybe it's a necessary evil, but where possible I want to capture that kind of information in a more structured way.
2) Do users need to write this messaging? They may do that now with VACOLS, but do they still need to do with Caseflow? I'm not sure.
3) Is there a way to extend the task model we already have to do some of this? i.e. could each hold get it's own hold task? Something like that.
My gut says more user research is needed before implementing something like this. If we can't extend Tsaks to do what we need, and we find this all is definitely necessary, then I think this is a good approach to that.
category column could add some desired structure to this event log.OnHoldTasks from Tasks themselves.For 2, if they still need the messaging, which it seems like they do then doing something like this seems preferable to having them use email.
My high level opinion on this is that it sounds like it could work — however, it's a difficult (and subjective) determination whether or not it's a little heavy-handed. I think to be confident in one approach or another, I'd like to have more information about potential uses for the TaskEvent class that are not described here. I describe some alternative methods for achieving the same goals @lowellrex mentions, would love some more thoughts on why or why not those alternatives are suitable to compare them with this.
t.datetime "assigned_at"
t.datetime "started_at"
t.datetime "completed_at"
t.datetime "placed_on_hold_at"
to TaskEvents? If we don't, I sort of worry about splitting state changes in two different places, it could lead us to a very confusing and contradictory long-term place. On the flipside, splitting it out querying for common information about tasks more involved. It also seems like the migration may be a lot of effort.
Messaging
Currently there is no way for a Task's assignee to include a message to the assigner when the assignee completes the Task. We could offer the assignee the option to add a note (as a TaskEvent) to the Task they are completing. We could then display that in the Case Timeline and rely on the assigner looking in the Case Timeline for that information, or we could pluck the final TaskEvent off of the parent Task's child Task and show it in the Case Snapshot.
I wonder if this could be accomplished without the TaskEvent class. If we added a "completion_note" field to every Task, we could still display it in the Case Timeline or the Case Snapshot, right? Are there any downsides to doing it that way?
Multiple holds
If a co-located staffer creates a hold for Task that was previously put on hold we overwrite the previous on hold information. I suspect this on hold information may be important when trying to understand the timeline of an appeal if it took an extraordinarily long time to process (say there are three extension requests granted we will only record one in the Task table).
Could we also store information about multiple holds in a JSON field? Or could we create a Hold class with a one-to-many relationship with Task?
I appreciate you separating and defining two entities that I have been referring to both as "notes".
Would these two entities populate an equivalent field in the TaskEvent idea, or two separate fields? (I may need help clarifying my question.)
Re: Diaries. I agree that our users have asked for these notes, and agree that this ask might be coming from (1) their current use of VACOLS, (2) this detailed information can be valuable for other users trying to figure out the story and status of a case (for example, if a Veteran calls Lit Support), and (3) their desire to explain their actions on cases/tasks to explain their productivity.
Re: Messaging. I know we have 4 different "queues" going on right now - attorney, judge, co-located, and generic, but all of them have some form of messaging so I agree that this is a proven need. I think it helps us accomplish users being able to see all of their work in their queue.
Re: Multiple holds: Saving information about when/how long holds were put on tasks that had multiple holds.
Regarding multiple holds: @amprokop I'm generally against putting a JSON column to store structured information. If that's really the approach we want to take then it seems at least hold information should be split out into its own table. That said, an alternative could be to create a new "HoldTask" type. This task would automatically expire after a certain period of time. It would be a subtask of the whatever task is on hold. Some advantages of this:
1) We can remove the hold information fields from task. That information would just live in the hold sub-task itself. This also means that to determine if a task is on hold, we can just look to see if it has an active child task.
2) Hold tasks can be completed, since they're just regular tasks. i.e. one workflow is the mail team receives the relevant mail that ends the hold, they search for the veteran, see there's a hold task, and completes it.
@laurjpeterson regarding how we would differentiate diaries and messages in this new event log, I think we have a few options supposing we go forward with this new table: 1) Add a column to determine the category of the event so that we can more precisely differentiate between diaries and messages so we can display them differently on the case details screen, or 2) Not differentiate between those two types of note in the database and rely on folks reading the notes that have accumulated on an appeal in the case timeline view to determine what they need to know.
Re: multiple holds: I am very much in favor of the HoldTask type @mdbenjam outlines above. ➕to all of that!
Implemented by #12167
Also see PR #16325 as part of the "Appeal Narrative" project, which extracts task and other records for presentation as a table of events for an appeal.
Most helpful comment
See also: Turning the Database Inside Out