fix(checks): scope foreground refreshes by provider

This commit is contained in:
Brennan Benson
2026-07-22 21:10:25 -07:00
parent 2cb50bbbb5
commit 7bfb5e1557
3 changed files with 151 additions and 30 deletions
@@ -134,7 +134,11 @@ import {
shouldPollChecksPanelRuntimeSshStatus,
type ChecksPanelGitStatusSnapshot
} from './checks-panel-git-status-snapshot'
import { resolveChecksPanelPRRefreshRequest } from './checks-panel-pr-refresh-request'
import {
getChecksPanelForegroundReviewEvidenceKey,
resolveChecksPanelPRRefreshRequest,
resolveChecksPanelReviewEvidenceProvider
} from './checks-panel-pr-refresh-request'
import { installWindowVisibilityInterval } from '@/lib/window-visibility-interval'
import { useMountedRef } from '@/hooks/useMountedRef'
import { callRuntimeRpc, getActiveRuntimeTarget } from '@/runtime/runtime-rpc-client'
@@ -965,7 +969,22 @@ export default function ChecksPanel(): React.JSX.Element {
hostedReviewCreation?.review?.number ??
checksPanelReviewLookupResult.openReviewUrl ??
'unknown'
const unrenderedReviewEvidenceProvider = hostedReviewCreation?.provider ?? hostedReview?.provider
const unrenderedReviewEvidenceProvider = resolveChecksPanelReviewEvidenceProvider({
linkedGitHubPR: linkedPR,
linkedGitLabMR,
linkedBitbucketPR,
linkedAzureDevOpsPR,
linkedGiteaPR,
eligibilityProvider: hostedReviewCreation?.provider,
cachedProvider: hostedReview?.provider
})
const foregroundReviewEvidenceKey = getChecksPanelForegroundReviewEvidenceKey({
refreshContextKey,
reviewEvidenceIdentity: unrenderedReviewEvidenceIdentity,
reviewEvidenceProvider: unrenderedReviewEvidenceProvider,
hasUnrenderedReviewEvidence,
isGitHubReviewContext
})
// Confirmed readiness from the last eligibility snapshot, not live canCreate (which would be circular and flap during transient failures).
const hardErrorObservedAt =
isGitHubReviewContext && hardRefreshError && hardRefreshError.contextKey === panelContextKey
@@ -1359,7 +1378,7 @@ export default function ChecksPanel(): React.JSX.Element {
}, [agentComposerState?.commentResolution, stateRequestKey])
useEffect(() => {
if (!hasUnrenderedReviewEvidence || !isPanelVisible) {
if (foregroundReviewEvidenceKey === null || !isPanelVisible) {
foregroundedUnrenderedReviewKeyRef.current = null
}
if (isPanelVisible && repo && !isFolder && branch) {
@@ -1376,17 +1395,17 @@ export default function ChecksPanel(): React.JSX.Element {
})
// Why: the gh-based refresh coordinator is GitHub-only; running it elsewhere gave a spurious gh_unavailable error hiding a valid composer.
if (activeWorktreeId && isGitHubReviewContext) {
const evidenceKey = `${refreshContextKey}::${unrenderedReviewEvidenceIdentity}`
const refreshRequest = resolveChecksPanelPRRefreshRequest({
cachedHasPR: prCachedHasPR,
cachedFetchedAt: prFetchedAt ?? null,
panelVisibleSince: panelVisibleSinceRef.current,
hasUnrenderedReviewEvidence,
reviewEvidenceProvider: unrenderedReviewEvidenceProvider,
hasRequestedForegroundRefresh: foregroundedUnrenderedReviewKeyRef.current === evidenceKey
hasUnrenderedReviewEvidence: foregroundReviewEvidenceKey !== null,
hasRequestedForegroundRefresh:
foregroundReviewEvidenceKey !== null &&
foregroundedUnrenderedReviewKeyRef.current === foregroundReviewEvidenceKey
})
if (refreshRequest.reason === 'active' && hasUnrenderedReviewEvidence) {
foregroundedUnrenderedReviewKeyRef.current = evidenceKey
if (refreshRequest.reason === 'active' && foregroundReviewEvidenceKey !== null) {
foregroundedUnrenderedReviewKeyRef.current = foregroundReviewEvidenceKey
}
enqueueGitHubPRRefresh(activeWorktreeId, refreshRequest.reason, refreshRequest.priority)
}
@@ -1397,7 +1416,7 @@ export default function ChecksPanel(): React.JSX.Element {
enqueueGitHubPRRefresh,
fallbackGitHubPRNumber,
fetchHostedReviewForBranch,
hasUnrenderedReviewEvidence,
foregroundReviewEvidenceKey,
isFolder,
isGitHubReviewContext,
isPanelVisible,
@@ -1409,9 +1428,6 @@ export default function ChecksPanel(): React.JSX.Element {
linkedPR,
prCachedHasPR,
prFetchedAt,
refreshContextKey,
unrenderedReviewEvidenceIdentity,
unrenderedReviewEvidenceProvider,
repo
])
@@ -1,5 +1,73 @@
import { describe, expect, it } from 'vitest'
import { resolveChecksPanelPRRefreshRequest } from './checks-panel-pr-refresh-request'
import {
getChecksPanelForegroundReviewEvidenceKey,
resolveChecksPanelPRRefreshRequest,
resolveChecksPanelReviewEvidenceProvider
} from './checks-panel-pr-refresh-request'
describe('resolveChecksPanelReviewEvidenceProvider', () => {
const noLinkedReviews = {
linkedGitHubPR: null,
linkedGitLabMR: null,
linkedBitbucketPR: null,
linkedAzureDevOpsPR: null,
linkedGiteaPR: null
}
it.each([
['linkedGitHubPR', 'github'],
['linkedGitLabMR', 'gitlab'],
['linkedBitbucketPR', 'bitbucket'],
['linkedAzureDevOpsPR', 'azure-devops'],
['linkedGiteaPR', 'gitea']
] as const)('lets an explicit %s link outrank stale cached metadata', (linkedField, provider) => {
expect(
resolveChecksPanelReviewEvidenceProvider({
...noLinkedReviews,
[linkedField]: 42,
cachedProvider: 'unsupported'
})
).toBe(provider)
})
it('uses eligibility before cached provider metadata when no review is linked', () => {
expect(
resolveChecksPanelReviewEvidenceProvider({
...noLinkedReviews,
eligibilityProvider: 'bitbucket',
cachedProvider: 'gitlab'
})
).toBe('bitbucket')
})
})
describe('getChecksPanelForegroundReviewEvidenceKey', () => {
const input = {
refreshContextKey: 'worktree::cache::branch',
reviewEvidenceIdentity: 42,
hasUnrenderedReviewEvidence: true,
isGitHubReviewContext: true
} as const
it('keeps optimistic and confirmed GitHub evidence on one request key', () => {
const optimisticKey = getChecksPanelForegroundReviewEvidenceKey(input)
const confirmedKey = getChecksPanelForegroundReviewEvidenceKey({
...input,
reviewEvidenceProvider: 'github'
})
expect(optimisticKey).toBe('worktree::cache::branch::github::42')
expect(confirmedKey).toBe(optimisticKey)
})
it('clears the request key when evidence switches to another provider', () => {
expect(
getChecksPanelForegroundReviewEvidenceKey({
...input,
reviewEvidenceProvider: 'gitlab'
})
).toBeNull()
})
})
describe('resolveChecksPanelPRRefreshRequest', () => {
it('uses an active refresh for a cached miss from before the checks panel became visible', () => {
@@ -56,18 +124,6 @@ describe('resolveChecksPanelPRRefreshRequest', () => {
).toEqual({ reason: 'swr', priority: 30 })
})
it('does not promote non-GitHub review evidence into an active GitHub lookup', () => {
expect(
resolveChecksPanelPRRefreshRequest({
cachedHasPR: null,
cachedFetchedAt: null,
panelVisibleSince: 200,
hasUnrenderedReviewEvidence: true,
reviewEvidenceProvider: 'gitlab'
})
).toEqual({ reason: 'swr', priority: 30 })
})
it('keeps populated or unknown cache entries on the background path', () => {
expect(
resolveChecksPanelPRRefreshRequest({
@@ -7,7 +7,6 @@ type ChecksPanelPRRefreshRequestInput = {
panelVisibleSince: number | null
// A known-but-unrendered review needs one foreground lookup to resolve its transient state.
hasUnrenderedReviewEvidence?: boolean
reviewEvidenceProvider?: HostedReviewProvider
hasRequestedForegroundRefresh?: boolean
}
@@ -16,6 +15,58 @@ type ChecksPanelPRRefreshRequest = {
priority: number
}
type ChecksPanelReviewEvidenceProviderInput = {
linkedGitHubPR: number | null
linkedGitLabMR: number | null
linkedBitbucketPR: number | null
linkedAzureDevOpsPR: number | null
linkedGiteaPR: number | null
eligibilityProvider?: HostedReviewProvider | undefined
cachedProvider?: HostedReviewProvider | undefined
}
type ChecksPanelForegroundReviewEvidenceKeyInput = {
refreshContextKey: string
reviewEvidenceIdentity: number | string
reviewEvidenceProvider?: HostedReviewProvider | undefined
hasUnrenderedReviewEvidence: boolean
isGitHubReviewContext: boolean
}
export function resolveChecksPanelReviewEvidenceProvider(
input: ChecksPanelReviewEvidenceProviderInput
): HostedReviewProvider | undefined {
if (input.linkedGitHubPR !== null) {
return 'github'
}
if (input.linkedGitLabMR !== null) {
return 'gitlab'
}
if (input.linkedBitbucketPR !== null) {
return 'bitbucket'
}
if (input.linkedAzureDevOpsPR !== null) {
return 'azure-devops'
}
if (input.linkedGiteaPR !== null) {
return 'gitea'
}
return input.eligibilityProvider ?? input.cachedProvider
}
export function getChecksPanelForegroundReviewEvidenceKey(
input: ChecksPanelForegroundReviewEvidenceKeyInput
): string | null {
if (
!input.hasUnrenderedReviewEvidence ||
!input.isGitHubReviewContext ||
(input.reviewEvidenceProvider !== undefined && input.reviewEvidenceProvider !== 'github')
) {
return null
}
return `${input.refreshContextKey}::github::${input.reviewEvidenceIdentity}`
}
export function resolveChecksPanelPRRefreshRequest(
input: ChecksPanelPRRefreshRequestInput
): ChecksPanelPRRefreshRequest {
@@ -25,9 +76,7 @@ export function resolveChecksPanelPRRefreshRequest(
input.panelVisibleSince !== null &&
input.cachedFetchedAt < input.panelVisibleSince
const unresolvedEvidenceNeedsForeground =
input.hasUnrenderedReviewEvidence &&
input.cachedHasPR !== true &&
(input.reviewEvidenceProvider === undefined || input.reviewEvidenceProvider === 'github')
input.hasUnrenderedReviewEvidence && input.cachedHasPR !== true
if (
!input.hasRequestedForegroundRefresh &&