From 59c351a4e089c7ba9c4b60a3cf38135066e2b446 Mon Sep 17 00:00:00 2001 From: isaacwang-sentry Date: Mon, 6 Apr 2026 13:40:53 -0700 Subject: [PATCH 1/5] feat(autofix): Register autofix-retry-from-step feature flag Add a new Flagpole feature flag to gate "Retry from step" buttons on Autofix v3 cards. This is primarily useful for local Seer testing, allowing developers to re-run individual autofix steps without restarting the entire flow. Co-Authored-By: Claude Opus 4.6 --- src/sentry/features/temporary.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sentry/features/temporary.py b/src/sentry/features/temporary.py index b67a8ad03124cd..cf126354c0c63b 100644 --- a/src/sentry/features/temporary.py +++ b/src/sentry/features/temporary.py @@ -318,6 +318,8 @@ def register_temporary_features(manager: FeatureManager) -> None: manager.add("organizations:autofix-on-explorer", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True) # Enable Autofix to use Seer Explorer V2 designs manager.add("organizations:autofix-on-explorer-v2", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True) + # Enable "Retry from step" buttons on Autofix v3 cards (for local Seer testing) + manager.add("organizations:autofix-retry-from-step", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True) # Enable Seer Workflows in Slack manager.add("organizations:seer-slack-workflows", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True) # Enable new compact issue alert UI in Slack From 3c52843183aa9fcd8e41fed80dd030e49d7a5932 Mon Sep 17 00:00:00 2001 From: isaacwang-sentry Date: Mon, 6 Apr 2026 15:02:27 -0700 Subject: [PATCH 2/5] feat(autofix): Thread insert_index through explorer API for retry Pass insert_index from the API serializer through trigger_autofix_explorer to client.continue_run. When provided, Seer truncates blocks after that index, enabling retry-from-step to properly reset downstream steps. Co-Authored-By: Claude Opus 4.6 --- src/sentry/seer/autofix/autofix_agent.py | 2 ++ src/sentry/seer/endpoints/group_ai_autofix.py | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/sentry/seer/autofix/autofix_agent.py b/src/sentry/seer/autofix/autofix_agent.py index 2e0898cc375f7c..0901b60a14b85f 100644 --- a/src/sentry/seer/autofix/autofix_agent.py +++ b/src/sentry/seer/autofix/autofix_agent.py @@ -200,6 +200,7 @@ def trigger_autofix_explorer( stopping_point: AutofixStoppingPoint | None = None, intelligence_level: Literal["low", "medium", "high"] = "low", user_context: str | None = None, + insert_index: int | None = None, ) -> int: """ Start or continue an Explorer-based autofix run. @@ -247,6 +248,7 @@ def trigger_autofix_explorer( prompt_metadata=prompt_metadata, artifact_key=artifact_key, artifact_schema=artifact_schema, + insert_index=insert_index, ) payload = { diff --git a/src/sentry/seer/endpoints/group_ai_autofix.py b/src/sentry/seer/endpoints/group_ai_autofix.py index d2ccb4f613c8d5..a9c3bc6fa20bf8 100644 --- a/src/sentry/seer/endpoints/group_ai_autofix.py +++ b/src/sentry/seer/endpoints/group_ai_autofix.py @@ -129,6 +129,10 @@ class ExplorerAutofixRequestSerializer(CamelSnakeSerializer): required=False, help_text="Optional repository name for which to create the pull request. Do not pass a repository name to create pull requests in all relevant repositories.", ) + insert_index = serializers.IntegerField( + required=False, + help_text="Block index to insert at. When provided, truncates blocks after this point for retry-from-step.", + ) def validate(self, data: dict[str, Any]) -> dict[str, Any]: stopping_point = data.get("stopping_point", None) @@ -289,6 +293,7 @@ def _post_explorer(self, request: Request, group: Group) -> Response: run_id=run_id, intelligence_level=data["intelligence_level"], user_context=data.get("user_context"), + insert_index=data.get("insert_index"), ) return Response({"run_id": run_id}, status=status.HTTP_202_ACCEPTED) except SeerPermissionError as e: From f40e2733cb1e0b6db90eb45ee40852bd21478fc4 Mon Sep 17 00:00:00 2001 From: isaacwang-sentry Date: Mon, 6 Apr 2026 15:22:26 -0700 Subject: [PATCH 3/5] ref(autofix): Remove unused autofix-retry-from-step feature flag The retry buttons are no longer gated behind a feature flag, so this registration is unnecessary. Co-Authored-By: Claude Opus 4.6 --- src/sentry/features/temporary.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sentry/features/temporary.py b/src/sentry/features/temporary.py index cf126354c0c63b..b67a8ad03124cd 100644 --- a/src/sentry/features/temporary.py +++ b/src/sentry/features/temporary.py @@ -318,8 +318,6 @@ def register_temporary_features(manager: FeatureManager) -> None: manager.add("organizations:autofix-on-explorer", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True) # Enable Autofix to use Seer Explorer V2 designs manager.add("organizations:autofix-on-explorer-v2", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True) - # Enable "Retry from step" buttons on Autofix v3 cards (for local Seer testing) - manager.add("organizations:autofix-retry-from-step", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True) # Enable Seer Workflows in Slack manager.add("organizations:seer-slack-workflows", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True) # Enable new compact issue alert UI in Slack From de0bc7805c7c8e0ff6e7cf036c28f47555b8b529 Mon Sep 17 00:00:00 2001 From: isaacwang-sentry Date: Tue, 7 Apr 2026 10:51:59 -0700 Subject: [PATCH 4/5] fix(test): Add insert_index to trigger_autofix_explorer mock assertion The test_stopping_point test checks exact kwargs passed to trigger_autofix_explorer. Add the new insert_index=None parameter to match the updated function signature. Co-Authored-By: Claude Opus 4.6 --- tests/sentry/seer/endpoints/test_group_ai_autofix.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/sentry/seer/endpoints/test_group_ai_autofix.py b/tests/sentry/seer/endpoints/test_group_ai_autofix.py index e892e451bf051e..647f9669f5dd34 100644 --- a/tests/sentry/seer/endpoints/test_group_ai_autofix.py +++ b/tests/sentry/seer/endpoints/test_group_ai_autofix.py @@ -940,6 +940,7 @@ def test_stopping_point(self, mock_trigger_explorer): run_id=None, intelligence_level="low", user_context=None, + insert_index=None, ) @patch("sentry.seer.autofix.autofix._call_autofix") From f299f7af945aa9c6b6d1edc497a389a6d08f6fe2 Mon Sep 17 00:00:00 2001 From: isaacwang-sentry Date: Tue, 7 Apr 2026 15:21:16 -0700 Subject: [PATCH 5/5] test(autofix): Add test for insert_index pass-through in explorer API Verify that insert_index from the POST request is threaded through to trigger_autofix_explorer for retry-from-step functionality. Co-Authored-By: Claude Opus 4.6 --- .../seer/endpoints/test_group_ai_autofix.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/sentry/seer/endpoints/test_group_ai_autofix.py b/tests/sentry/seer/endpoints/test_group_ai_autofix.py index 647f9669f5dd34..9df8e7a2251649 100644 --- a/tests/sentry/seer/endpoints/test_group_ai_autofix.py +++ b/tests/sentry/seer/endpoints/test_group_ai_autofix.py @@ -943,6 +943,34 @@ def test_stopping_point(self, mock_trigger_explorer): insert_index=None, ) + @patch("sentry.seer.endpoints.group_ai_autofix.trigger_autofix_explorer") + def test_insert_index_passed_through(self, mock_trigger_explorer): + """POST passes insert_index to trigger_autofix_explorer for retry-from-step.""" + for flag in EXPLORER_FLAGS: + mock_trigger_explorer.reset_mock() + group = self.create_group() + mock_trigger_explorer.return_value = 123 + + self.login_as(user=self.user) + with self.feature(flag): + response = self.client.post( + self._get_url(group.id, mode="explorer"), + data={"step": "solution", "run_id": 42, "insert_index": 3}, + format="json", + ) + + assert response.status_code == 202, f"Failed for {flag}: {response.data}" + mock_trigger_explorer.assert_called_once_with( + group=group, + step=AutofixStep.SOLUTION, + referrer=AutofixReferrer.GROUP_AUTOFIX_ENDPOINT, + stopping_point=None, + run_id=42, + intelligence_level="low", + user_context=None, + insert_index=3, + ) + @patch("sentry.seer.autofix.autofix._call_autofix") @patch("sentry.seer.autofix.autofix._get_trace_tree_for_event") @patch("sentry.tasks.seer.autofix.check_autofix_status.apply_async")