Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions packages/core/src/inbox/reportFiltering.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,25 @@ describe("filterReportsBySearch", () => {

describe("buildSignalReportListOrdering", () => {
it.each([
["total_weight", "desc", "status,-total_weight"],
["created_at", "asc", "status,created_at"],
["signal_count", "desc", "status,-signal_count"],
] as const)("orders by status then %s (%s)", (field, direction, expected) => {
expect(buildSignalReportListOrdering(field, direction)).toBe(expected);
});
["total_weight", "desc", "status,-total_weight,priority"],
["created_at", "asc", "status,created_at,priority"],
["signal_count", "desc", "status,-signal_count,priority"],
] as const)(
"orders by status then %s (%s), tiebreaking by priority",
(field, direction, expected) => {
expect(buildSignalReportListOrdering(field, direction)).toBe(expected);
},
);

it.each([
["priority", "asc", "status,priority,-created_at"],
["priority", "desc", "status,-priority,-created_at"],
] as const)(
"tiebreaks %s (%s) by newest first",
(field, direction, expected) => {
expect(buildSignalReportListOrdering(field, direction)).toBe(expected);
},
);

it("does not float the current user's reports via ordering", () => {
expect(buildSignalReportListOrdering("priority", "asc")).not.toContain(
Expand Down
8 changes: 7 additions & 1 deletion packages/core/src/inbox/reportFiltering.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ export function buildStatusFilterParam(statuses: SignalReportStatus[]): string {
* Comma-separated `ordering` for the signal report list API:
* 1. Status rank (ready first – semantic server-side rank, always applied)
* 2. Toolbar-selected field (priority, total_weight, created_at, etc.)
* 3. A tiebreak so reports the primary field can't separate come back in a
* sensible order. Sorting by priority (a coarse 5-bucket P0–P4 rank) tiebreaks
* by `-created_at` so the newest report wins within a tier; every other field
* tiebreaks by `priority` so the most urgent report wins. The server applies
* the clauses in order (and falls back to `id`), so this only breaks ties.
*
* Reviewer scope is applied via the `suggested_reviewers` param, not ordering:
* a `-is_suggested_reviewer` tiebreak would float the user's reports to the top
Expand All @@ -75,7 +80,8 @@ export function buildSignalReportListOrdering(
direction: "asc" | "desc",
): string {
const fieldKey = direction === "desc" ? `-${field}` : field;
return `status,${fieldKey}`;
const tiebreak = field === "priority" ? "-created_at" : "priority";
return ["status", fieldKey, tiebreak].join(",");
}

export function buildSuggestedReviewerFilterParam(
Expand Down
Loading