Flow
Before and after, step by step
1Resolve a team
Before: swapped for its members. Now: stays one team ID.
2Read
Before: people filter on the tracker. Now: read every page and match people or teams myself.
3Stop
Before: stop on an empty page. Now: stop on the tracker last-page signal or a truly empty page.
4Write
Before: one assignment per member. Now: one team assignment, removed as one.
The ops dashboard didn't know a team could own a task. My tracker sends two lists with each task: the people on it and the teams on it. The dashboard kept the people and threw the teams away. So a task owned only by a team showed up as "Unassigned."
The view I use most is "mine plus my team's." To build it, the dashboard swapped the team name for the user IDs of everyone on the team. Then it asked the tracker for tasks assigned to those people. The tracker can filter by people, but not by teams. So a task owned by the team itself had no person on it to match, and it never showed up. Tasks that team members had grabbed for themselves showed up in the team view instead.
Writes had the same problem. Picking the team in the assign panel sent every member's ID. The task got a pile of personal assignments, and nothing said the team owned it.
None of it throws an error. A list missing the team's work looks just like a list where the team has no work.
Person IDs and team IDs, kept apart
Now a person stays a person and a team stays a team. The resolver returns two lists, and every layer passes both along. Nothing gets merged into one list of user IDs.
The dashboard also keeps the team field now, and shows team names as owners.
Since the tracker can't filter by team, I do it myself. If the view includes a team, the dashboard asks for every task, page by page. It keeps a task if any of its people or any of its teams is one I asked for. Views with only people still let the tracker filter.
The page that said "done" too early
The loop that reads pages stopped when a page came back empty. That worked when the tracker did the filtering. With my own filter in front, an empty page might just mean "nothing for me on this page." Keep the old rule and the scan quits at the first page of other people's work.
So the stop check ignores my filter.
The scan ends only when the tracker says the page is last or the raw page is empty, no matter what my filter kept.
A test gives the reader a page with no matches while the tracker says more pages follow. The reader must not call it the end.
Raising the page ceiling for full scans
Reading every page costs many more requests. I raised the highest allowed page limit a lot. The default stays small, and only views filtered by assignee and the "give me everything" mode ask for the bigger limit. The scan still stops as soon as the tracker says it hit the last page. Another test hides the only match one page past the old limit and checks that it gets found.
Writes that name the team
Assigning work now sends people and teams in separate fields, using the tracker's own team assignment. Assigning a team makes one team assignment. If I copied it onto each member, those copies would go stale when someone joins or leaves. Removing the team removes just that one assignment. And a request that names no people and no teams gets turned away.