From 8a3aa4182ae2a89e00f59fa9e68b9930d5a28c08 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 1 Nov 2026 20:27:19 +0000 Subject: [PATCH] ref(flags): Graduate organizations:autofix-browser-notifications in the UI The flag has been GA (rollout 100, conditions []) since automator #9026 on 2026-08-03. Its only non-GA segment disables the feature for the `sandbox` org, which `isDemoModeActive()` expresses in the frontend. Co-authored-by: charlie.luo --- .../events/autofix/useExplorerAutofix.tsx | 8 +++--- .../v3/seerEnableNotifications.spec.tsx | 27 ++++++++++++------- .../autofix/v3/seerEnableNotifications.tsx | 5 +++- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/static/app/components/events/autofix/useExplorerAutofix.tsx b/static/app/components/events/autofix/useExplorerAutofix.tsx index b6df65d5637c..f42382afa525 100644 --- a/static/app/components/events/autofix/useExplorerAutofix.tsx +++ b/static/app/components/events/autofix/useExplorerAutofix.tsx @@ -29,6 +29,7 @@ import {trackAnalytics} from 'sentry/utils/analytics'; import {apiOptions} from 'sentry/utils/api/apiOptions'; import {getApiUrl} from 'sentry/utils/api/getApiUrl'; import {defined} from 'sentry/utils/defined'; +import {isDemoModeActive} from 'sentry/utils/demoMode'; import {useApi} from 'sentry/utils/useApi'; import {useOrganization} from 'sentry/utils/useOrganization'; import {useUser} from 'sentry/utils/useUser'; @@ -854,10 +855,9 @@ export function useExplorerAutofix( await invalidation; } - if ( - organization.features.includes('autofix-browser-notifications') && - serviceWorker.isServiceWorkerSupported - ) { + // The sandbox can start Seer runs to showcase AI, but announcing them + // to a demo visitor's OS is not part of that pitch. + if (!isDemoModeActive() && serviceWorker.isServiceWorkerSupported) { serviceWorker.controller .postMessage({ type: 'event', diff --git a/static/app/components/events/autofix/v3/seerEnableNotifications.spec.tsx b/static/app/components/events/autofix/v3/seerEnableNotifications.spec.tsx index a4306455d4c4..4ea6858a7ffb 100644 --- a/static/app/components/events/autofix/v3/seerEnableNotifications.spec.tsx +++ b/static/app/components/events/autofix/v3/seerEnableNotifications.spec.tsx @@ -4,6 +4,9 @@ import {render, screen} from 'sentry-test/reactTestingLibrary'; import {SeerEnableNotifications} from 'sentry/components/events/autofix/v3/seerEnableNotifications'; import {AutofixChatProvider} from 'sentry/components/seer/autofixChatContext'; +import {isDemoModeActive} from 'sentry/utils/demoMode'; + +jest.mock('sentry/utils/demoMode'); // Service workers and the Notification API do not exist in jsdom, and // `supportsNotifications` is read once at module scope, so there is no store or @@ -33,6 +36,7 @@ describe('SeerEnableNotifications', () => { beforeEach(() => { MockApiClient.clearMockResponses(); + jest.mocked(isDemoModeActive).mockReturnValue(false); promptsRequest = MockApiClient.addMockResponse({ url: '/organizations/org-slug/prompts-activity/', body: {data: {}}, @@ -40,28 +44,31 @@ describe('SeerEnableNotifications', () => { }); it('offers to notify while a run is processing', async () => { - render(, { - organization: OrganizationFixture({features: ['autofix-browser-notifications']}), - }); + render(); expect(await screen.findByRole('button', {name: NOTIFY_BUTTON})).toBeInTheDocument(); expect(promptsRequest).toHaveBeenCalled(); }); + it('stays quiet in the demo sandbox', () => { + jest.mocked(isDemoModeActive).mockReturnValue(true); + + render(); + + expect(promptsRequest).not.toHaveBeenCalled(); + expect(screen.queryByRole('button', {name: NOTIFY_BUTTON})).not.toBeInTheDocument(); + }); + it('stays quiet in code mode, where the agent owns the run', () => { render( , { - // Code mode needs the Explorer's own prerequisites alongside its flag, - // and a chat that can take the run. + // Code mode needs the Explorer's own prerequisites, and a chat that can + // take the run. organization: OrganizationFixture({ - features: [ - 'autofix-browser-notifications', - 'seer-explorer-code-mode-tools', - 'seer-explorer', - ], + features: ['seer-explorer-code-mode-tools', 'seer-explorer'], openMembership: true, hideAiFeatures: false, }), diff --git a/static/app/components/events/autofix/v3/seerEnableNotifications.tsx b/static/app/components/events/autofix/v3/seerEnableNotifications.tsx index 2bfa0e958a38..9ffd70ff457c 100644 --- a/static/app/components/events/autofix/v3/seerEnableNotifications.tsx +++ b/static/app/components/events/autofix/v3/seerEnableNotifications.tsx @@ -17,6 +17,7 @@ import {useServiceWorker} from 'sentry/serviceWorker/client/serviceWorkerContext import {useNotificationPermission} from 'sentry/serviceWorker/client/useNotificationPermission'; import type {RequestMessage} from 'sentry/serviceWorker/types'; import {trackAnalytics} from 'sentry/utils/analytics'; +import {isDemoModeActive} from 'sentry/utils/demoMode'; import {useOrganization} from 'sentry/utils/useOrganization'; const SUCCESS_VISIBLE_DURATION_MS = 25_000; @@ -47,7 +48,9 @@ export function SeerEnableNotifications({status}: Props) { const analyticsArea = useAnalyticsArea(); const isEligible = - organization.features.includes('autofix-browser-notifications') && + // The sandbox can start Seer runs to showcase AI, but asking a demo visitor + // for browser notification permission is not part of that pitch. + !isDemoModeActive() && // In code mode the run is handed to the agent and followed in chat, so an // offer to announce it from here would point at the wrong surface. !isCodeMode &&