Skip to content

ref(uptime): remove uptime-runtime-assertions feature flag#110478

Merged
evanpurkhiser merged 1 commit intomasterfrom
evanpurkhiser/ref-uptime-remove-uptime-runtime-assertions-feature-flag
Mar 16, 2026
Merged

ref(uptime): remove uptime-runtime-assertions feature flag#110478
evanpurkhiser merged 1 commit intomasterfrom
evanpurkhiser/ref-uptime-remove-uptime-runtime-assertions-feature-flag

Conversation

@evanpurkhiser
Copy link
Member

GA'd in options-automator, so remove all flag checks and clean up the
conditional logic that gated assertion validation and preview execution.

@evanpurkhiser evanpurkhiser requested a review from a team as a code owner March 11, 2026 21:10
@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Mar 11, 2026
Copy link
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Removing backend flag breaks frontend assertions UI
    • Updated useUptimeAssertionFeatures hook to always return true for hasRuntimeAssertions since the feature is now GA'd, and removed obsolete tests that checked disabled feature flag behavior.

Create PR

Or push these changes by commenting:

@cursor push 901560fb6d
Preview (901560fb6d)
diff --git a/static/app/views/alerts/rules/uptime/uptimeAlertForm.spec.tsx b/static/app/views/alerts/rules/uptime/uptimeAlertForm.spec.tsx
--- a/static/app/views/alerts/rules/uptime/uptimeAlertForm.spec.tsx
+++ b/static/app/views/alerts/rules/uptime/uptimeAlertForm.spec.tsx
@@ -432,12 +432,7 @@
   });
 
   it('sends assertion in create request when feature is enabled', async () => {
-    const orgWithAssertions = OrganizationFixture({
-      features: ['uptime-runtime-assertions'],
-    });
-    OrganizationStore.onUpdate(orgWithAssertions);
-
-    render(<UptimeAlertForm />, {organization: orgWithAssertions});
+    render(<UptimeAlertForm />);
     await screen.findByText('Configure Request');
 
     // Verify the Verification section is shown
@@ -453,7 +448,7 @@
     await userEvent.type(name, 'Rule with Assertion');
 
     const createMock = MockApiClient.addMockResponse({
-      url: `/projects/${orgWithAssertions.slug}/${project.slug}/uptime/`,
+      url: `/projects/${organization.slug}/${project.slug}/uptime/`,
       method: 'POST',
     });
 
@@ -490,25 +485,8 @@
     );
   });
 
-  it('does not show assertions when feature is disabled', async () => {
-    const orgWithoutAssertions = OrganizationFixture({
-      features: [],
-    });
-    OrganizationStore.onUpdate(orgWithoutAssertions);
 
-    render(<UptimeAlertForm />, {organization: orgWithoutAssertions});
-    await screen.findByText('Configure Request');
-
-    // Verify the Verification section is NOT shown
-    expect(screen.queryByText('Verification')).not.toBeInTheDocument();
-  });
-
   it('renders and updates assertion for existing rule', async () => {
-    const orgWithAssertions = OrganizationFixture({
-      features: ['uptime-runtime-assertions'],
-    });
-    OrganizationStore.onUpdate(orgWithAssertions);
-
     const assertion: UptimeAssertion = {
       root: {
         op: UptimeOpType.AND,
@@ -532,11 +510,11 @@
       assertion,
     });
 
-    render(<UptimeAlertForm rule={rule} />, {organization: orgWithAssertions});
+    render(<UptimeAlertForm rule={rule} />);
     await screen.findByText('Verification');
 
     const updateMock = MockApiClient.addMockResponse({
-      url: `/projects/${orgWithAssertions.slug}/${project.slug}/uptime/${rule.id}/`,
+      url: `/projects/${organization.slug}/${project.slug}/uptime/${rule.id}/`,
       method: 'PUT',
     });
 
@@ -555,12 +533,7 @@
   it('displays assertion compilation errors', async () => {
     const addErrorMessageSpy = jest.spyOn(indicators, 'addErrorMessage');
 
-    const orgWithAssertions = OrganizationFixture({
-      features: ['uptime-runtime-assertions'],
-    });
-    OrganizationStore.onUpdate(orgWithAssertions);
-
-    render(<UptimeAlertForm />, {organization: orgWithAssertions});
+    render(<UptimeAlertForm />);
     await screen.findByText('Verification');
 
     await selectEvent.select(input('Project'), project.slug);
@@ -573,7 +546,7 @@
     await userEvent.type(name, 'Rule with Invalid Assertion');
 
     MockApiClient.addMockResponse({
-      url: `/projects/${orgWithAssertions.slug}/${project.slug}/uptime/`,
+      url: `/projects/${organization.slug}/${project.slug}/uptime/`,
       method: 'POST',
       statusCode: 400,
       body: {
@@ -609,12 +582,7 @@
   it('displays assertion serialization error toast', async () => {
     const addErrorMessageSpy = jest.spyOn(indicators, 'addErrorMessage');
 
-    const orgWithAssertions = OrganizationFixture({
-      features: ['uptime-runtime-assertions'],
-    });
-    OrganizationStore.onUpdate(orgWithAssertions);
-
-    render(<UptimeAlertForm />, {organization: orgWithAssertions});
+    render(<UptimeAlertForm />);
     await screen.findByText('Verification');
 
     await selectEvent.select(input('Project'), project.slug);
@@ -627,7 +595,7 @@
     await userEvent.type(name, 'Rule with Invalid Assertion');
 
     MockApiClient.addMockResponse({
-      url: `/projects/${orgWithAssertions.slug}/${project.slug}/uptime/`,
+      url: `/projects/${organization.slug}/${project.slug}/uptime/`,
       method: 'POST',
       statusCode: 400,
       body: {
@@ -649,11 +617,6 @@
   });
 
   it('preserves null assertion when editing rule without assertions', async () => {
-    const orgWithAssertions = OrganizationFixture({
-      features: ['uptime-runtime-assertions'],
-    });
-    OrganizationStore.onUpdate(orgWithAssertions);
-
     // Rule with no assertions (assertion: null from API)
     const rule = UptimeRuleFixture({
       name: 'Rule without Assertion',
@@ -663,7 +626,7 @@
       assertion: null,
     });
 
-    render(<UptimeAlertForm rule={rule} />, {organization: orgWithAssertions});
+    render(<UptimeAlertForm rule={rule} />);
     await screen.findByText('Verification');
 
     // Should show empty UI - Add Assertion button but no assertion inputs
@@ -675,7 +638,7 @@
     ).toBeLessThanOrEqual(0);
 
     const updateMock = MockApiClient.addMockResponse({
-      url: `/projects/${orgWithAssertions.slug}/${project.slug}/uptime/${rule.id}/`,
+      url: `/projects/${organization.slug}/${project.slug}/uptime/${rule.id}/`,
       method: 'PUT',
     });
 
@@ -692,98 +655,4 @@
     );
   });
 
-  it('preserves null assertion when feature flag is disabled', async () => {
-    // When the feature flag is off, the assertions field isn't rendered,
-    // so we need to ensure the original null assertion is preserved on submit
-    const orgWithoutAssertions = OrganizationFixture({
-      features: [],
-    });
-    OrganizationStore.onUpdate(orgWithoutAssertions);
-
-    const rule = UptimeRuleFixture({
-      name: 'Rule without Assertion',
-      projectSlug: project.slug,
-      url: 'https://existing-url.com',
-      owner: ActorFixture(),
-      assertion: null,
-    });
-
-    render(<UptimeAlertForm rule={rule} />, {organization: orgWithoutAssertions});
-    await screen.findByText('Configure Request');
-
-    // Verification section should NOT be shown
-    expect(screen.queryByText('Verification')).not.toBeInTheDocument();
-
-    const updateMock = MockApiClient.addMockResponse({
-      url: `/projects/${orgWithoutAssertions.slug}/${project.slug}/uptime/${rule.id}/`,
-      method: 'PUT',
-    });
-
-    await userEvent.click(screen.getByRole('button', {name: 'Save Rule'}));
-
-    // Should submit null assertion, not the empty default structure
-    expect(updateMock).toHaveBeenCalledWith(
-      expect.anything(),
-      expect.objectContaining({
-        data: expect.objectContaining({
-          assertion: null,
-        }),
-      })
-    );
-  });
-
-  it('preserves existing assertion when feature flag is disabled', async () => {
-    // When the feature flag is off but the rule has existing assertions,
-    // those assertions should be preserved on submit
-    const orgWithoutAssertions = OrganizationFixture({
-      features: [],
-    });
-    OrganizationStore.onUpdate(orgWithoutAssertions);
-
-    const existingAssertion: UptimeAssertion = {
-      root: {
-        op: UptimeOpType.AND,
-        children: [
-          {
-            id: 'test-1',
-            op: UptimeOpType.STATUS_CODE_CHECK,
-            operator: {cmp: UptimeComparisonType.EQUALS},
-            value: 200,
-          },
-        ],
-        id: 'root-1',
-      },
-    };
-
-    const rule = UptimeRuleFixture({
-      name: 'Rule with Assertion',
-      projectSlug: project.slug,
-      url: 'https://existing-url.com',
-      owner: ActorFixture(),
-      assertion: existingAssertion,
-    });
-
-    render(<UptimeAlertForm rule={rule} />, {organization: orgWithoutAssertions});
-    await screen.findByText('Configure Request');
-
-    // Verification section should NOT be shown
-    expect(screen.queryByText('Verification')).not.toBeInTheDocument();
-
-    const updateMock = MockApiClient.addMockResponse({
-      url: `/projects/${orgWithoutAssertions.slug}/${project.slug}/uptime/${rule.id}/`,
-      method: 'PUT',
-    });
-
-    await userEvent.click(screen.getByRole('button', {name: 'Save Rule'}));
-
-    // Should submit the existing assertion unchanged
-    expect(updateMock).toHaveBeenCalledWith(
-      expect.anything(),
-      expect.objectContaining({
-        data: expect.objectContaining({
-          assertion: existingAssertion,
-        }),
-      })
-    );
-  });
 });

diff --git a/static/app/views/alerts/rules/uptime/useUptimeAssertionFeatures.tsx b/static/app/views/alerts/rules/uptime/useUptimeAssertionFeatures.tsx
--- a/static/app/views/alerts/rules/uptime/useUptimeAssertionFeatures.tsx
+++ b/static/app/views/alerts/rules/uptime/useUptimeAssertionFeatures.tsx
@@ -3,9 +3,7 @@
 export function useUptimeAssertionFeatures() {
   const organization = useOrganization();
 
-  const hasRuntimeAssertions = organization.features.includes(
-    'uptime-runtime-assertions'
-  );
+  const hasRuntimeAssertions = true;
   const hasAiAssertionSuggestions =
     hasRuntimeAssertions &&
     organization.features.includes('uptime-ai-assertion-suggestions') &&

This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.

@github-actions
Copy link
Contributor

Backend Test Failures

Failures on 53f5aea in this run:

tests/sentry/uptime/endpoints/test_detector.py::OrganizationDetectorDetailsPutTest::test_updatelog
tests/sentry/uptime/endpoints/test_detector.py:158: in test_update
    self.get_success_response(
src/sentry/testutils/cases.py:629: in get_success_response
    assert_status_code(response, status_code)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 201
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_detector.py::OrganizationDetectorIndexPostTest::test_create_detectorlog
tests/sentry/uptime/endpoints/test_detector.py:326: in test_create_detector
    response = self.get_success_response(
src/sentry/testutils/cases.py:629: in get_success_response
    assert_status_code(response, status_code)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 202
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_detector.py::OrganizationDetectorIndexPostTest::test_create_detector_non_superuser_cannot_set_auto_detected_modelog
tests/sentry/uptime/endpoints/test_detector.py:394: in test_create_detector_non_superuser_cannot_set_auto_detected_mode
    response = self.get_error_response(
src/sentry/testutils/cases.py:663: in get_error_response
    assert_status_code(response, status_code)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 401
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_detector.py::OrganizationDetectorIndexPostTest::test_create_detector_optional_fieldslog
tests/sentry/uptime/endpoints/test_detector.py:361: in test_create_detector_optional_fields
    response = self.get_success_response(
src/sentry/testutils/cases.py:629: in get_success_response
    assert_status_code(response, status_code)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 202
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_project_uptime_alert_details.py::ProjectUptimeAlertDetailsPutEndpointTest::test_alllog
tests/sentry/uptime/endpoints/test_project_uptime_alert_details.py:56: in test_all
    resp = self.get_success_response(
src/sentry/testutils/cases.py:636: in get_success_response
    assert_status_code(response, status.HTTP_200_OK)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 201
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_project_uptime_alert_details.py::ProjectUptimeAlertDetailsPutEndpointTest::test_disabling_response_capture_also_disables_system_flaglog
tests/sentry/uptime/endpoints/test_project_uptime_alert_details.py:277: in test_disabling_response_capture_also_disables_system_flag
    self.get_success_response(
src/sentry/testutils/cases.py:636: in get_success_response
    assert_status_code(response, status.HTTP_200_OK)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 201
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_project_uptime_alert_details.py::ProjectUptimeAlertDetailsPutEndpointTest::test_enviromentlog
tests/sentry/uptime/endpoints/test_project_uptime_alert_details.py:112: in test_enviroment
    resp = self.get_success_response(
src/sentry/testutils/cases.py:636: in get_success_response
    assert_status_code(response, status.HTTP_200_OK)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 201
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_project_uptime_alert_details.py::ProjectUptimeAlertDetailsPutEndpointTest::test_response_capture_enabledlog
tests/sentry/uptime/endpoints/test_project_uptime_alert_details.py:247: in test_response_capture_enabled
    resp = self.get_success_response(
src/sentry/testutils/cases.py:636: in get_success_response
    assert_status_code(response, status.HTTP_200_OK)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 201
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_project_uptime_alert_details.py::ProjectUptimeAlertDetailsPutEndpointTest::test_status_disablelog
tests/sentry/uptime/endpoints/test_project_uptime_alert_details.py:217: in test_status_disable
    resp = self.get_success_response(
src/sentry/testutils/cases.py:636: in get_success_response
    assert_status_code(response, status.HTTP_200_OK)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 201
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_project_uptime_alert_details.py::ProjectUptimeAlertDetailsPutEndpointTest::test_status_enablelog
tests/sentry/uptime/endpoints/test_project_uptime_alert_details.py:231: in test_status_enable
    resp = self.get_success_response(
src/sentry/testutils/cases.py:636: in get_success_response
    assert_status_code(response, status.HTTP_200_OK)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 201
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_project_uptime_alert_details.py::ProjectUptimeAlertDetailsPutEndpointTest::test_status_enable_no_seat_assignmentlog
tests/sentry/uptime/endpoints/test_project_uptime_alert_details.py:312: in test_status_enable_no_seat_assignment
    assert "status" in resp.data or "non_field_errors" in resp.data
E   assert ('status' in {'detail': 'Internal Error', 'errorId': None} or 'non_field_errors' in {'detail': 'Internal Error', 'errorId': None})
E    +  where {'detail': 'Internal Error', 'errorId': None} = <Response status_code=500, "application/json">.data
E    +  and   {'detail': 'Internal Error', 'errorId': None} = <Response status_code=500, "application/json">.data
tests/sentry/uptime/endpoints/test_project_uptime_alert_details.py::ProjectUptimeAlertDetailsPutEndpointTest::test_teamlog
tests/sentry/uptime/endpoints/test_project_uptime_alert_details.py:142: in test_team
    resp = self.get_success_response(
src/sentry/testutils/cases.py:636: in get_success_response
    assert_status_code(response, status.HTTP_200_OK)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 201
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_project_uptime_alert_details.py::ProjectUptimeAlertDetailsPutEndpointTest::test_userlog
tests/sentry/uptime/endpoints/test_project_uptime_alert_details.py:127: in test_user
    resp = self.get_success_response(
src/sentry/testutils/cases.py:636: in get_success_response
    assert_status_code(response, status.HTTP_200_OK)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 201
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py::ProjectUptimeAlertIndexPostEndpointTest::testlog
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py:25: in test
    resp = self.get_success_response(
src/sentry/testutils/cases.py:641: in get_success_response
    assert_status_code(response, 200, 300)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 300
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py::ProjectUptimeAlertIndexPostEndpointTest::test_custom_thresholdslog
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py:69: in test_custom_thresholds
    resp = self.get_success_response(
src/sentry/testutils/cases.py:641: in get_success_response
    assert_status_code(response, 200, 300)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 300
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py::ProjectUptimeAlertIndexPostEndpointTest::test_headers_body_methodlog
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py:169: in test_headers_body_method
    resp = self.get_success_response(
src/sentry/testutils/cases.py:641: in get_success_response
    assert_status_code(response, 200, 300)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 300
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py::ProjectUptimeAlertIndexPostEndpointTest::test_headers_body_method_already_existslog
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py:188: in test_headers_body_method_already_exists
    resp = self.get_success_response(
src/sentry/testutils/cases.py:641: in get_success_response
    assert_status_code(response, 200, 300)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 300
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py::ProjectUptimeAlertIndexPostEndpointTest::test_mode_superadminlog
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py:147: in test_mode_superadmin
    resp = self.get_success_response(
src/sentry/testutils/cases.py:641: in get_success_response
    assert_status_code(response, 200, 300)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 300
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py::ProjectUptimeAlertIndexPostEndpointTest::test_no_environmentlog
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py:86: in test_no_environment
    resp = self.get_success_response(
src/sentry/testutils/cases.py:641: in get_success_response
    assert_status_code(response, 200, 300)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 300
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py::ProjectUptimeAlertIndexPostEndpointTest::test_no_ownerlog
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py:100: in test_no_owner
    resp = self.get_success_response(
src/sentry/testutils/cases.py:641: in get_success_response
    assert_status_code(response, 200, 300)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 300
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py::ProjectUptimeAlertIndexPostEndpointTest::test_no_seat_assignmentlog
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py:310: in test_no_seat_assignment
    resp = self.get_success_response(
src/sentry/testutils/cases.py:641: in get_success_response
    assert_status_code(response, 200, 300)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 300
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py::ProjectUptimeAlertIndexPostEndpointTest::test_over_limitlog
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py:284: in test_over_limit
    self.get_success_response(
src/sentry/testutils/cases.py:641: in get_success_response
    assert_status_code(response, 200, 300)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 300
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py::ProjectUptimeAlertIndexPostEndpointTest::test_owner_team_admin_can_assign_any_teamlog
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py:424: in test_owner_team_admin_can_assign_any_team
    resp = self.get_success_response(
src/sentry/testutils/cases.py:641: in get_success_response
    assert_status_code(response, 200, 300)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 300
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py::ProjectUptimeAlertIndexPostEndpointTest::test_owner_team_member_allowedlog
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py:397: in test_owner_team_member_allowed
    resp = self.get_success_response(
src/sentry/testutils/cases.py:641: in get_success_response
    assert_status_code(response, 200, 300)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 300
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py::ProjectUptimeAlertIndexPostEndpointTest::test_owner_team_open_membership_allows_any_teamlog
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py:454: in test_owner_team_open_membership_allows_any_team
    resp = self.get_success_response(
src/sentry/testutils/cases.py:641: in get_success_response
    assert_status_code(response, 200, 300)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 300
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py::ProjectUptimeAlertIndexPostEndpointTest::test_set_trace_samplinglog
tests/sentry/uptime/endpoints/test_project_uptime_alert_index.py:52: in test_set_trace_sampling
    resp = self.get_success_response(
src/sentry/testutils/cases.py:641: in get_success_response
    assert_status_code(response, 200, 300)
src/sentry/testutils/asserts.py:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
E   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')
E   assert 500 < 300
E    +  where 500 = <Response status_code=500, "application/json">.status_code
tests/sentry/uptime/endpoints/test_validators.py::UptimeMonitorDataSourceValidatorTest::test_simplelog
tests/sentry/uptime/endpoints/test_validators.py:86: in test_simple
    assert validator.is_valid()
.venv/lib/python3.13/site-packages/rest_framework/serializers.py:225: in is_valid
    self._validated_data = self.run_validation(self.initial_data)
.venv/lib/python3.13/site-packages/rest_framework/serializers.py:447: in run_validation
    value = self.validate(value)
src/sentry/uptime/endpoints/validators.py:563: in validate
    _validate_check_config(attrs, self.instance, self.context["organization"], user)
src/sentry/uptime/endpoints/validators.py:176: in _validate_check_config
    result = checker_api.invoke_checker_validator(check_config, region)
src/sentry/uptime/checker_api.py:44: in invoke_checker_validator
    result = requests.post(
.venv/lib/python3.13/site-packages/requests/api.py:115: in post
    return request("post", url, data=data, json=json, **kwargs)
.venv/lib/python3.13/site-packages/requests/api.py:59: in request
    return session.request(method=method, url=url, **kwargs)
.venv/lib/python3.13/site-packages/requests/sessions.py:575: in request
    prep = self.prepare_request(req)
.venv/lib/python3.13/site-packages/requests/sessions.py:484: in prepare_request
    p.prepare(
.venv/lib/python3.13/site-packages/requests/models.py:367: in prepare
    self.prepare_url(url, params)
.venv/lib/python3.13/site-packages/requests/models.py:444: in prepare_url
    raise InvalidURL(f"Invalid URL {url!r}: No host supplied")
E   requests.exceptions.InvalidURL: Invalid URL 'http:///validate_check': No host supplied
tests/sentry/uptime/endpoints/test_validators.py::UptimeDomainCheckFailureValidatorTest::test_create_creates_detector_with_correct_structurelog
tests/sentry/uptime/endpoints/test_validators.py:570: in test_create_creates_detector_with_correct_structure
    assert validator.is_valid(), validator.errors
.venv/lib/python3.13/site-packages/rest_framework/serializers.py:225: in is_valid
    self._validated_data = self.run_validation(self.initial_data)
.venv/lib/python3.13/site-packages/rest_framework/serializers.py:444: in run_validation
    value = self.to_internal_value(data)
.venv/lib/python3.13/site-packages/rest_framework/serializers.py:501: in to_internal_value
    validated_value = field.run_validation(primitive_value)
.venv/lib/python3.13/site-packages/rest_framework/fields.py:538: in run_validation
    value = self.to_internal_value(data)
src/sentry/runner/initializer.py:479: in to_internal_value
    return [self.child.run_validation(item) for item in data]
.venv/lib/python3.13/site-packages/rest_framework/serializers.py:447: in run_validation
    value = self.validate(value)
src/sentry/uptime/endpoints/validators.py:563: in validate
    _validate_check_config(attrs, self.instance, self.context["organization"], user)
src/sentry/uptime/endpoints/validators.py:176: in _validate_check_config
    result = checker_api.invoke_checker_validator(check_config, region)
src/sentry/uptime/checker_api.py:44: in invoke_checker_validator
    result = requests.post(
.venv/lib/python3.13/site-packages/requests/api.py:115: in post
    return request("post", url, data=data, json=json, **kwargs)
.venv/lib/python3.13/site-packages/requests/api.py:59: in request
    return session.request(method=method, url=url, **kwargs)
.venv/lib/python3.13/site-packages/requests/sessions.py:575: in request
    prep = self.prepare_request(req)
.venv/lib/python3.13/site-packages/requests/sessions.py:484: in prepare_request
    p.prepare(
.venv/lib/python3.13/site-packages/requests/models.py:367: in prepare
    self.prepare_url(url, params)
.venv/lib/python3.13/site-packages/requests/models.py:444: in prepare_url
    raise InvalidURL(f"Invalid URL {url!r}: No host supplied")
E   requests.exceptions.InvalidURL: Invalid URL 'http:///validate_check': No host supplied
tests/sentry/uptime/endpoints/test_validators.py::UptimeDomainCheckFailureValidatorTest::test_create_creates_uptime_subscriptionlog
tests/sentry/uptime/endpoints/test_validators.py:648: in test_create_creates_uptime_subscription
    assert validator.is_valid(), validator.errors
.venv/lib/python3.13/site-packages/rest_framework/serializers.py:225: in is_valid
    self._validated_data = self.run_validation(self.initial_data)
.venv/lib/python3.13/site-packages/rest_framework/serializers.py:444: in run_validation
    value = self.to_internal_value(data)
.venv/lib/python3.13/site-packages/rest_framework/serializers.py:501: in to_internal_value
    validated_value = field.run_validation(primitive_value)
.venv/lib/python3.13/site-packages/rest_framework/fields.py:538: in run_validation
    value = self.to_internal_value(data)
src/sentry/runner/initializer.py:479: in to_internal_value
    return [self.child.run_validation(item) for item in data]
.venv/lib/python3.13/site-packages/rest_framework/serializers.py:447: in run_validation
    value = self.validate(value)
src/sentry/uptime/endpoints/validators.py:563: in validate
    _validate_check_config(attrs, self.instance, self.context["organization"], user)
src/sentry/uptime/endpoints/validators.py:176: in _validate_check_config
    result = checker_api.invoke_checker_validator(check_config, region)
src/sentry/uptime/checker_api.py:44: in invoke_checker_validator
    result = requests.post(
.venv/lib/python3.13/site-packages/requests/api.py:115: in post
    return request("post", url, data=data, json=json, **kwargs)
.venv/lib/python3.13/site-packages/requests/api.py:59: in request
    return session.request(method=method, url=url, **kwargs)
.venv/lib/python3.13/site-packages/requests/sessions.py:575: in request
    prep = self.prepare_request(req)
.venv/lib/python3.13/site-packages/requests/sessions.py:484: in prepare_request
    p.prepare(
.venv/lib/python3.13/site-packages/requests/models.py:367: in prepare
    self.prepare_url(url, params)
.venv/lib/python3.13/site-packages/requests/models.py:444: in prepare_url
    raise InvalidURL(f"Invalid URL {url!r}: No host supplied")
E   requests.exceptions.InvalidURL: Invalid URL 'http:///validate_check': No host supplied
tests/sentry/uptime/endpoints/test_validators.py::UptimeDomainCheckFailureValidatorTest::test_create_enabled_assigns_seatlog
tests/sentry/uptime/endpoints/test_validators.py:204: in test_create_enabled_assigns_seat
    assert validator.is_valid(), validator.errors
.venv/lib/python3.13/site-packages/rest_framework/serializers.py:225: in is_valid
    self._validated_data = self.run_validation(self.initial_data)
.venv/lib/python3.13/site-packages/rest_framework/serializers.py:444: in run_validation
    value = self.to_internal_value(data)
.venv/lib/python3.13/site-packages/rest_framework/serializers.py:501: in to_internal_value
    validated_value = field.run_validation(primitive_value)
.venv/lib/python3.13/site-packages/rest_framework/fields.py:538: in run_validation
    value = self.to_internal_value(data)
src/sentry/runner/initializer.py:479: in to_internal_value
    return [self.child.run_validation(item) for item in data]
.venv/lib/python3.13/site-packages/rest_framework/serializers.py:447: in run_validation
    value = self.validate(value)
src/sentry/uptime/endpoints/validators.py:563: in validate
    _validate_check_config(attrs, self.instance, self.context["organization"], user)
src/sentry/uptime/endpoints/validators.py:176: in _validate_check_config
    result = checker_api.invoke_checker_validator(check_config, region)
src/sentry/uptime/checker_api.py:44: in invoke_checker_validator
    result = requests.post(
.venv/lib/python3.13/site-packages/requests/api.py:115: in post
    return request("post", url, data=data, json=json, **kwargs)
.venv/lib/python3.13/site-packages/requests/api.py:59: in request
    return session.request(method=method, url=url, **kwargs)
.venv/lib/python3.13/site-packages/requests/sessions.py:575: in request
    prep = self.prepare_request(req)
.venv/lib/python3.13/site-packages/requests/sessions.py:484: in prepare_request
    p.prepare(
.venv/lib/python3.13/site-packages/requests/models.py:367: in prepare
    self.prepare_url(url, params)
.venv/lib/python3.13/site-packages/requests/models.py:444: in prepare_url
    raise InvalidURL(f"Invalid URL {url!r}: No host supplied")
E   requests.exceptions.InvalidURL: Invalid URL 'http:///validate_check': No host supplied

... and 9 more failures.

@evanpurkhiser evanpurkhiser force-pushed the evanpurkhiser/ref-uptime-remove-uptime-runtime-assertions-feature-flag branch from 499cd85 to ccbb75c Compare March 11, 2026 23:48
@evanpurkhiser evanpurkhiser requested a review from a team as a code owner March 11, 2026 23:48
Copy link
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

def _validate_check_config(
attrs, uptime_subscription: UptimeSubscription | None, organization, user
):
assertions_enabled = features.has(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused parameters after feature flag removal

Low Severity

The organization and user parameters of _validate_check_config are now completely unused after the features.has("organizations:uptime-runtime-assertions", ...) check was removed. The function body no longer references either parameter, but all three callers still pass them. These dead parameters add confusion about the function's actual dependencies.

Fix in Cursor Fix in Web

GA'd in options-automator, so remove all flag checks and clean up the
conditional logic that gated assertion validation and preview execution.
@evanpurkhiser evanpurkhiser force-pushed the evanpurkhiser/ref-uptime-remove-uptime-runtime-assertions-feature-flag branch from cf74167 to ab53e0f Compare March 16, 2026 20:01
@evanpurkhiser evanpurkhiser merged commit 662f607 into master Mar 16, 2026
78 checks passed
@evanpurkhiser evanpurkhiser deleted the evanpurkhiser/ref-uptime-remove-uptime-runtime-assertions-feature-flag branch March 16, 2026 20:46
JonasBa pushed a commit that referenced this pull request Mar 16, 2026
GA'd in options-automator, so remove all flag checks and clean up the
conditional logic that gated assertion validation and preview execution.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Backend Automatically applied to PRs that change backend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants