diff --git a/ui/src/components/Sidebar.tsx b/ui/src/components/Sidebar.tsx index 613baa6278..429ca9c42b 100644 --- a/ui/src/components/Sidebar.tsx +++ b/ui/src/components/Sidebar.tsx @@ -68,7 +68,10 @@ export function Sidebar() { resourceKey: "live-runs", queryKey: liveRunsQueryKey, enabled: !!selectedCompanyId, - refetchInterval: 10_000, + // Event-sourced via LiveUpdatesProvider (#9627) + reconnect reconcile — no + // interval poll needed. Polling here also re-armed React Query's timer on + // every live-event cache write, a major source of steady-state churn. + refetchInterval: false, leaderOnly: true, }); const { data: liveRuns, dataUpdatedAt: liveRunsUpdatedAt } = useQuery({ diff --git a/ui/src/components/SidebarAgents.test.tsx b/ui/src/components/SidebarAgents.test.tsx index 1cdfdd49a8..3ee1aeea3b 100644 --- a/ui/src/components/SidebarAgents.test.tsx +++ b/ui/src/components/SidebarAgents.test.tsx @@ -702,7 +702,8 @@ describe("SidebarAgents", () => { expect(agentLinkLabels(container)).toEqual(["Alpha"]); await act(async () => { - await vi.advanceTimersByTimeAsync(1); + await vi.advanceTimersByTimeAsync(5); + await vi.advanceTimersByTimeAsync(0); }); expect(agentLinkLabels(container)).toEqual(["Alpha", "Bravo", "Charlie"]); }); @@ -758,12 +759,14 @@ describe("SidebarAgents", () => { expect(agentLinkLabels(container)).toEqual(["Alpha", "Bravo"]); await act(async () => { - await vi.advanceTimersByTimeAsync(60_001); + await vi.advanceTimersByTimeAsync(60_005); + await vi.advanceTimersByTimeAsync(0); }); expect(agentLinkLabels(container)).toEqual(["Bravo"]); await act(async () => { - await vi.advanceTimersByTimeAsync(60_000); + await vi.advanceTimersByTimeAsync(60_005); + await vi.advanceTimersByTimeAsync(0); }); expect(agentLinkLabels(container)).toEqual(["Alpha", "Bravo", "Charlie"]); }); diff --git a/ui/src/components/SidebarAgents.tsx b/ui/src/components/SidebarAgents.tsx index da1f9dde4f..b344364d2f 100644 --- a/ui/src/components/SidebarAgents.tsx +++ b/ui/src/components/SidebarAgents.tsx @@ -339,7 +339,8 @@ export function SidebarAgents({ streamlined = false }: { streamlined?: boolean } resourceKey: "live-runs", queryKey: liveRunsQueryKey, enabled: !!selectedCompanyId, - refetchInterval: 10_000, + // Event-sourced via LiveUpdatesProvider (#9627); no interval poll needed. + refetchInterval: false, leaderOnly: true, }); const { data: liveRuns, dataUpdatedAt: liveRunsUpdatedAt } = useQuery({ diff --git a/ui/src/pages/ExecutionWorkspaceDetail.tsx b/ui/src/pages/ExecutionWorkspaceDetail.tsx index e130cf1b21..c2cac0b629 100644 --- a/ui/src/pages/ExecutionWorkspaceDetail.tsx +++ b/ui/src/pages/ExecutionWorkspaceDetail.tsx @@ -445,7 +445,8 @@ function ExecutionWorkspaceIssuesList({ resourceKey: "live-runs", queryKey: liveRunsQueryKey, enabled: !!companyId, - refetchInterval: 5000, + // Event-sourced via LiveUpdatesProvider (#9627); no interval poll needed. + refetchInterval: false, leaderOnly: true, }); const { data: liveRuns, dataUpdatedAt: liveRunsUpdatedAt } = useQuery({ diff --git a/ui/src/pages/Inbox.tsx b/ui/src/pages/Inbox.tsx index f3ff80fe12..16355d1f5e 100644 --- a/ui/src/pages/Inbox.tsx +++ b/ui/src/pages/Inbox.tsx @@ -2,7 +2,6 @@ import { type ReactNode, useCallback, useEffect, useMemo, useRef, useState } fro import { Link, useLocation, useNavigate } from "@/lib/router"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { deriveOriginatingActor, INBOX_MINE_ISSUE_STATUS_FILTER } from "@paperclipai/shared"; -import { useVisibilityRefetchInterval } from "@/lib/polling"; import { usePublishSharedQueryData, useSharedPollingQuery } from "@/hooks/useSharedPolling"; import { approvalsApi } from "../api/approvals"; import { accessApi } from "../api/access"; @@ -917,14 +916,14 @@ export function Inbox() { refetchOnWindowFocus: false, staleTime: INBOX_HOT_PATH_STALE_MS, }); - const liveRunsRefetchInterval = useVisibilityRefetchInterval({ visibleMs: 5000 }); const liveRunsQueryKey = queryKeys.liveRuns(selectedCompanyId!); const sharedLiveRuns = useSharedPollingQuery({ companyId: selectedCompanyId, resourceKey: "live-runs", queryKey: liveRunsQueryKey, enabled: !!selectedCompanyId, - refetchInterval: liveRunsRefetchInterval, + // Event-sourced via LiveUpdatesProvider (#9627); no interval poll needed. + refetchInterval: false, leaderOnly: true, }); const { data: liveRuns, dataUpdatedAt: liveRunsUpdatedAt } = useQuery({ diff --git a/ui/src/pages/IssueDetail.tsx b/ui/src/pages/IssueDetail.tsx index 694fd42a70..acfc5ea85a 100644 --- a/ui/src/pages/IssueDetail.tsx +++ b/ui/src/pages/IssueDetail.tsx @@ -2,7 +2,6 @@ import { memo, useCallback, useEffect, useMemo, useRef, useState, type ChangeEve import { pickTextColorForPillBg } from "@/lib/color-contrast"; import { Link, useLocation, useNavigate, useNavigationType, useParams } from "@/lib/router"; import { useInfiniteQuery, useQuery, useMutation, useQueryClient, type InfiniteData, type QueryClient } from "@tanstack/react-query"; -import { useVisibilityRefetchInterval } from "@/lib/polling"; import { usePublishSharedQueryData, useSharedPollingQuery } from "@/hooks/useSharedPolling"; import { ApiError } from "../api/client"; import { issuesApi } from "../api/issues"; @@ -1684,14 +1683,14 @@ export function IssueDetail() { queryFn: () => issuesApi.list(resolvedCompanyId!, { parentId: issue!.parentId!, includeBlockedBy: true }), enabled: !!resolvedCompanyId && !!issue?.parentId, }); - const companyLiveRunsRefetchInterval = useVisibilityRefetchInterval({ visibleMs: 5000 }); const companyLiveRunsQueryKey = resolvedCompanyId ? queryKeys.liveRuns(resolvedCompanyId) : ["live-runs", "pending"] as const; const sharedCompanyLiveRuns = useSharedPollingQuery({ companyId: resolvedCompanyId, resourceKey: "live-runs", queryKey: companyLiveRunsQueryKey, enabled: !!resolvedCompanyId, - refetchInterval: companyLiveRunsRefetchInterval, + // Event-sourced via LiveUpdatesProvider (#9627); no interval poll needed. + refetchInterval: false, leaderOnly: true, }); const { data: companyLiveRuns, dataUpdatedAt: companyLiveRunsUpdatedAt } = useQuery({ diff --git a/ui/src/pages/Issues.tsx b/ui/src/pages/Issues.tsx index c523e6edfa..97e367c0e7 100644 --- a/ui/src/pages/Issues.tsx +++ b/ui/src/pages/Issues.tsx @@ -8,7 +8,6 @@ import { heartbeatsApi } from "../api/heartbeats"; import { useCompany } from "../context/CompanyContext"; import { useBreadcrumbs } from "../context/BreadcrumbContext"; import { collectLiveIssueIds } from "../lib/liveIssueIds"; -import { useVisibilityRefetchInterval } from "@/lib/polling"; import { usePublishSharedQueryData, useSharedPollingQuery } from "@/hooks/useSharedPolling"; import { queryKeys } from "../lib/queryKeys"; import { createIssueDetailLocationState } from "../lib/issueDetailBreadcrumb"; @@ -98,14 +97,14 @@ export function Issues() { enabled: !!selectedCompanyId, }); - const liveRunsRefetchInterval = useVisibilityRefetchInterval({ visibleMs: 5000 }); const liveRunsQueryKey = queryKeys.liveRuns(selectedCompanyId!); const sharedLiveRuns = useSharedPollingQuery({ companyId: selectedCompanyId, resourceKey: "live-runs", queryKey: liveRunsQueryKey, enabled: !!selectedCompanyId, - refetchInterval: liveRunsRefetchInterval, + // Event-sourced via LiveUpdatesProvider (#9627); no interval poll needed. + refetchInterval: false, leaderOnly: true, }); const { data: liveRuns, dataUpdatedAt: liveRunsUpdatedAt } = useQuery({ diff --git a/ui/src/pages/ProjectDetail.tsx b/ui/src/pages/ProjectDetail.tsx index 1c9b881bfd..b5bbcd03c2 100644 --- a/ui/src/pages/ProjectDetail.tsx +++ b/ui/src/pages/ProjectDetail.tsx @@ -241,7 +241,8 @@ function ProjectIssuesList({ projectId, companyId }: { projectId: string; compan resourceKey: "live-runs", queryKey: liveRunsQueryKey, enabled: !!companyId, - refetchInterval: 5000, + // Event-sourced via LiveUpdatesProvider (#9627); no interval poll needed. + refetchInterval: false, leaderOnly: true, }); const { data: liveRuns, dataUpdatedAt: liveRunsUpdatedAt } = useQuery({ @@ -317,7 +318,8 @@ function ProjectPluginOperationsList({ resourceKey: "live-runs", queryKey: liveRunsQueryKey, enabled: !!companyId, - refetchInterval: 5000, + // Event-sourced via LiveUpdatesProvider (#9627); no interval poll needed. + refetchInterval: false, leaderOnly: true, }); const { data: liveRuns, dataUpdatedAt: liveRunsUpdatedAt } = useQuery({ diff --git a/ui/src/pages/Routines.tsx b/ui/src/pages/Routines.tsx index 0b7e33d68e..58c02dce38 100644 --- a/ui/src/pages/Routines.tsx +++ b/ui/src/pages/Routines.tsx @@ -342,7 +342,8 @@ export function Routines() { resourceKey: "live-runs", queryKey: liveRunsQueryKey, enabled: !!selectedCompanyId && activeTab === "runs", - refetchInterval: 5000, + // Event-sourced via LiveUpdatesProvider (#9627); no interval poll needed. + refetchInterval: false, leaderOnly: true, }); const { data: liveRuns, dataUpdatedAt: liveRunsUpdatedAt } = useQuery({ diff --git a/ui/src/plugins/bridge-init.ts b/ui/src/plugins/bridge-init.ts index a279c5e0bd..f6370417bd 100644 --- a/ui/src/plugins/bridge-init.ts +++ b/ui/src/plugins/bridge-init.ts @@ -277,7 +277,8 @@ function PluginSdkIssuesList({ resourceKey: "live-runs", queryKey: liveRunsQueryKey, enabled: !!companyId, - refetchInterval: 5000, + // Event-sourced via LiveUpdatesProvider (#9627); no interval poll needed. + refetchInterval: false, leaderOnly: true, }); const { data: liveRuns, dataUpdatedAt: liveRunsUpdatedAt } = useQuery({