From a56641b082bd671bc3be67bd3e0096f14d2abb38 Mon Sep 17 00:00:00 2001 From: Charlie Luo Date: Tue, 1 Sep 2026 14:23:25 -0700 Subject: [PATCH] fix(monitors): Sort latest issues by last occurrence Use the latest issue last-seen time for monitor ordering. Refs ISWF-2969 Co-authored-by: Codex --- .../endpoints/organization_detector_index.py | 8 +++---- .../test_organization_detector_index.py | 24 +++++++++---------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/sentry/workflow_engine/endpoints/organization_detector_index.py b/src/sentry/workflow_engine/endpoints/organization_detector_index.py index 24dbed36b9af..45cd38464d0e 100644 --- a/src/sentry/workflow_engine/endpoints/organization_detector_index.py +++ b/src/sentry/workflow_engine/endpoints/organization_detector_index.py @@ -116,8 +116,8 @@ def convert_assignee_values(value: Iterable[str], projects: Sequence[Project], u "-type": "-type", "connectedWorkflows": "connected_workflows", "-connectedWorkflows": "-connected_workflows", - "latestGroup": F("latest_group_date_added").asc(nulls_first=True), - "-latestGroup": F("latest_group_date_added").desc(nulls_last=True), + "latestGroup": F("latest_group_last_seen").asc(nulls_first=True), + "-latestGroup": F("latest_group_last_seen").desc(nulls_last=True), "openIssues": F("open_issues_count").asc(nulls_first=True), "-openIssues": F("open_issues_count").desc(nulls_last=True), } @@ -319,10 +319,10 @@ def get( latest_detector_group_subquery = ( DetectorGroup.objects.filter(detector=OuterRef("pk")) .order_by("-date_added") - .values("date_added")[:1] + .values("group__last_seen")[:1] ) queryset = queryset.annotate( - latest_group_date_added=Subquery(latest_detector_group_subquery) + latest_group_last_seen=Subquery(latest_detector_group_subquery) ) elif sort_by_field == "openIssues": queryset = queryset.annotate( diff --git a/tests/sentry/workflow_engine/endpoints/test_organization_detector_index.py b/tests/sentry/workflow_engine/endpoints/test_organization_detector_index.py index 3649c895d02a..fca79258aa2a 100644 --- a/tests/sentry/workflow_engine/endpoints/test_organization_detector_index.py +++ b/tests/sentry/workflow_engine/endpoints/test_organization_detector_index.py @@ -300,45 +300,43 @@ def test_sort_by_latest_group(self) -> None: project=self.project, name="Detector 4 No Groups", type=MetricIssue.slug ) - group_1 = self.create_group(project=self.project) - group_2 = self.create_group(project=self.project) - group_3 = self.create_group(project=self.project) + group_1 = self.create_group(project=self.project, last_seen=before_now(hours=1)) + group_2 = self.create_group(project=self.project, last_seen=before_now(hours=3)) + group_3 = self.create_group(project=self.project, last_seen=before_now(hours=2)) - # detector_1 has the oldest group + # The issue creation order is intentionally the opposite of the occurrence order. detector_group_1 = DetectorGroup.objects.create(detector=detector_1, group=group_1) detector_group_1.date_added = before_now(hours=3) detector_group_1.save() - # detector_2 has the newest group detector_group_2 = DetectorGroup.objects.create(detector=detector_2, group=group_2) - detector_group_2.date_added = before_now(hours=1) # Most recent + detector_group_2.date_added = before_now(hours=1) detector_group_2.save() - # detector_3 has one in the middle detector_group_3 = DetectorGroup.objects.create(detector=detector_3, group=group_3) detector_group_3.date_added = before_now(hours=2) detector_group_3.save() - # Test descending sort (newest groups first) + # Test descending sort (latest occurrences first) response = self.get_success_response( self.organization.slug, qs_params={"project": self.project.id, "sortBy": "-latestGroup"} ) assert [d["name"] for d in response.data] == [ - detector_2.name, - detector_3.name, detector_1.name, + detector_3.name, + detector_2.name, detector_4.name, # No groups, should be last ] - # Test ascending sort (oldest groups first) + # Test ascending sort (oldest occurrences first) response2 = self.get_success_response( self.organization.slug, qs_params={"project": self.project.id, "sortBy": "latestGroup"} ) assert [d["name"] for d in response2.data] == [ detector_4.name, # No groups, should be first - detector_1.name, - detector_3.name, detector_2.name, + detector_3.name, + detector_1.name, ] def test_sort_by_open_issues(self) -> None: