fix(github): preserve runtime failure attribution

This commit is contained in:
Brennan Benson
2026-07-16 22:25:21 -07:00
parent c58eac518a
commit 4dd315dfbc
2 changed files with 82 additions and 2 deletions
@@ -6322,6 +6322,71 @@ describe('createGitHubSlice.fetchWorkItems source/error envelope', () => {
}
})
it('flags a GitHub outage returned by a remote runtime method', async () => {
const store = createTestStore()
const consoleWarn = vi.spyOn(console, 'warn').mockImplementation(() => {})
runtimeEnvironmentCall.mockResolvedValueOnce({
id: 'rpc-work-items-outage',
ok: false,
error: { code: 'runtime_error', message: 'HTTP 503: Service Unavailable' },
_meta: { runtimeId: 'remote-runtime' }
})
store.setState({
settings: { activeRuntimeEnvironmentId: 'env-1' },
repos: [{ id: 'runtime-repo-id', path: '/server/repo', name: 'repo', kind: 'git' }]
} as unknown as Partial<AppState>)
try {
const result = await store
.getState()
.fetchWorkItemsAcrossRepos(
[{ repoId: 'caller-repo-id', path: '/server/repo' }],
24,
100,
''
)
expect(result.githubUnavailable).toBe(true)
expect(result.failedCount).toBe(1)
} finally {
consoleWarn.mockRestore()
}
})
it('does not attribute a remote runtime transport timeout to GitHub', async () => {
const store = createTestStore()
const consoleWarn = vi.spyOn(console, 'warn').mockImplementation(() => {})
runtimeEnvironmentCall.mockResolvedValueOnce({
id: 'rpc-work-items-runtime-timeout',
ok: false,
error: {
code: 'runtime_unavailable',
message: 'Runtime request timed out before github.listWorkItems completed'
},
_meta: { runtimeId: null }
})
store.setState({
settings: { activeRuntimeEnvironmentId: 'env-1' },
repos: [{ id: 'runtime-repo-id', path: '/server/repo', name: 'repo', kind: 'git' }]
} as unknown as Partial<AppState>)
try {
const result = await store
.getState()
.fetchWorkItemsAcrossRepos(
[{ repoId: 'caller-repo-id', path: '/server/repo' }],
24,
100,
''
)
expect(result.githubUnavailable).toBe(false)
expect(result.failedCount).toBe(1)
} finally {
consoleWarn.mockRestore()
}
})
it('flags githubUnavailable while serving stale cached rows after a failed refresh', async () => {
const store = createTestStore()
const consoleWarn = vi.spyOn(console, 'warn').mockImplementation(() => {})
+17 -2
View File
@@ -39,7 +39,11 @@ import {
PER_REPO_FETCH_LIMIT
} from '../../../../shared/work-items'
import { deriveCheckStatusFromChecks, syncPRChecksStatus } from './github-checks'
import { callRuntimeRpc, getActiveRuntimeTarget } from '../../runtime/runtime-rpc-client'
import {
callRuntimeRpc,
getActiveRuntimeTarget,
RuntimeRpcCallError
} from '../../runtime/runtime-rpc-client'
import { getSettingsForRepoRuntimeOwner } from '@/lib/repo-runtime-owner'
import { settingsForProjectRowOwner } from './github-project-row-owner'
import { rightSidebarShowsPullRequestData } from '@/lib/right-sidebar-visibility'
@@ -418,6 +422,17 @@ function countGitHubWorkItemsForRepo(
})
}
function isGitHubUnavailableWorkItemsError(error: unknown): boolean {
// Why: remote-runtime transport failures can also say "timed out" or
// "unavailable". Only runtime_error came from the GitHub method itself;
// other RPC codes must not be attributed to GitHub.
if (error instanceof RuntimeRpcCallError && error.code !== 'runtime_error') {
return false
}
const message = error instanceof Error ? error.message : String(error)
return classifyGitHubUnavailable(message) !== null
}
export function projectViewCacheKey(
ownerType: GetProjectViewTableArgs['ownerType'],
owner: string,
@@ -2887,7 +2902,7 @@ export const createGitHubSlice: StateCreator<AppState, [], [], GitHubSlice> = (s
return [] as GitHubWorkItem[]
}
requestFailureCount += 1
if (classifyGitHubUnavailable(err instanceof Error ? err.message : String(err))) {
if (isGitHubUnavailableWorkItemsError(err)) {
unavailableFailureCount += 1
}
const key =