fix(runtime-status): re-list host catalog when the listing goes stale

Coverage matching cannot observe catalog edits made by another client or the
orca CLI, so gate hydration on catalog listing age too.

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Neil
2026-08-11 00:21:19 -07:00
co-authored by Orca
parent 001bcb8f9e
commit 171e2134fa
3 changed files with 38 additions and 1 deletions
@@ -1,5 +1,16 @@
import type { PublicKnownRuntimeEnvironment } from '../../../../shared/runtime-environments'
/** Matches the renderer's other catalog-style cache TTLs (checks, work items, Jira). */
export const RUNTIME_CATALOG_STALE_MS = 60_000
let lastCatalogListedAt = 0
/** Why: status coverage cannot observe catalog edits made by another client or the
* orca CLI, so an old-enough listing must be re-read even when coverage looks complete. */
export function isRuntimeCatalogListingStale(): boolean {
return Date.now() - lastCatalogListedAt > RUNTIME_CATALOG_STALE_MS
}
type RuntimeStatusHydrationDependencies = {
listEnvironments: () => Promise<PublicKnownRuntimeEnvironment[]>
getCurrentEnvironments: () => PublicKnownRuntimeEnvironment[]
@@ -67,6 +78,7 @@ export function createRuntimeStatusHydration({
markCatalogSettled()
return
}
lastCatalogListedAt = Date.now()
if (!revisionsMatch(getCurrentEnvironments(), revisionsAtListStart)) {
rerunRequested = true
continue
@@ -10,6 +10,7 @@ import {
RUNTIME_PROTOCOL_VERSION
} from '../../../../shared/protocol-version'
import { clearRuntimeCompatibilityCacheForTests } from '../../runtime/runtime-rpc-client'
import { RUNTIME_CATALOG_STALE_MS } from './runtime-status-hydration'
vi.mock('sonner', () => ({ toast: { error: vi.fn(), success: vi.fn(), info: vi.fn() } }))
vi.mock('@/lib/agent-status', async (importOriginal) => {
@@ -828,4 +829,25 @@ describe('fetchSettings runtime catalog probe', () => {
expect(runtimeEnvironmentList).toHaveBeenCalledTimes(1)
})
it('re-lists the catalog once the listing goes stale even though coverage still matches', async () => {
const environments = [makeRuntimeEnvironment('env-a')]
runtimeEnvironmentList.mockResolvedValue(environments)
const store = createTestStore()
const now = vi.spyOn(Date, 'now').mockReturnValue(1_000_000)
try {
await store.getState().fetchSettings()
await vi.waitFor(() => expect(store.getState().runtimeStatusByEnvironmentId.size).toBe(1))
await store.getState().fetchSettings()
expect(runtimeEnvironmentList).toHaveBeenCalledTimes(1)
now.mockReturnValue(1_000_000 + RUNTIME_CATALOG_STALE_MS + 1)
await store.getState().fetchSettings()
await vi.waitFor(() => expect(runtimeEnvironmentList).toHaveBeenCalledTimes(2))
} finally {
now.mockRestore()
}
})
})
+4 -1
View File
@@ -14,6 +14,7 @@ import { normalizeTerminalCustomThemes } from '../../../../shared/terminal-custo
import { normalizeTaskProviderSettings } from '../../../../shared/task-providers'
import { normalizeOpenInApplications } from '../../../../shared/open-in-applications'
import { createSettingsSearchState, type SettingsSearchState } from './settings-search-state'
import { isRuntimeCatalogListingStale } from './runtime-status-hydration'
import { normalizeDisabledTuiAgents } from '../../../../shared/tui-agent-selection'
import {
normalizeTuiAgentArgsRecord,
@@ -169,7 +170,9 @@ export const createSettingsSlice: StateCreator<AppState, [], [], SettingsSlice>
if (
!runtimeEnvironmentCatalogHydrated ||
runtimeEnvironmentIds.size !== runtimeStatusByEnvironmentId.size ||
runtimeEnvironments.some(({ id }) => !runtimeStatusByEnvironmentId.has(id))
runtimeEnvironments.some(({ id }) => !runtimeStatusByEnvironmentId.has(id)) ||
// Why: coverage is blind to catalog edits from another client or the orca CLI.
isRuntimeCatalogListingStale()
) {
void get().hydrateRuntimeEnvironmentStatuses()
}