fix(runtime): preserve diagnostic overlay lifecycle

This commit is contained in:
Merge Sim
2026-08-31 11:27:09 -07:00
parent a02948cb73
commit dd185cf7e4
4 changed files with 85 additions and 28 deletions
@@ -56,7 +56,7 @@ export function RuntimeServerRow({
state.runtimeStatusByEnvironmentId.get(environment.id)
)
const connectionState =
details?.status === 'loading'
details?.status === 'loading' && !runtimeStatusEntry?.status
? 'checking'
: runtimeStatusEntry
? getRuntimeServerConnectionState({
@@ -4,25 +4,16 @@ import type { RuntimeEnvironmentStatus } from './runtime-status'
const diagnosticsGenerationByEnvironment = new Map<string, number>()
export function updateRuntimeEnvironmentStatusOverlay<
T extends {
runtimeStatusByEnvironmentId: ReadonlyMap<string, RuntimeEnvironmentStatus>
}
>(
state: T,
export function updateRuntimeEnvironmentStatusOverlay(
state: Map<string, RuntimeEnvironmentStatus>,
environmentId: string,
status: RuntimeEnvironmentStatus
): T | { runtimeStatusByEnvironmentId: ReadonlyMap<string, RuntimeEnvironmentStatus> } {
const current = state.runtimeStatusByEnvironmentId.get(environmentId)
): Map<string, RuntimeEnvironmentStatus> {
const current = state.get(environmentId)
if (!current || current.status?.runtimeId !== status.status?.runtimeId) {
return state
}
return {
runtimeStatusByEnvironmentId: new Map(state.runtimeStatusByEnvironmentId).set(
environmentId,
status
)
}
return new Map(state).set(environmentId, status)
}
export function acceptRuntimeEnvironmentDiagnosticsGeneration(
@@ -0,0 +1,69 @@
import type { RemoteRuntimeSharedConnectionDiagnostics } from '../../../../shared/remote-runtime-shared-control-types'
import type { RuntimeEnvironmentStatus } from './runtime-status'
import * as diagnosticsGeneration from './runtime-status-diagnostics-generation'
export function publishRuntimeEnvironmentDiagnostics(args: {
environmentId: string
transportGeneration: number
diagnostics: RemoteRuntimeSharedConnectionDiagnostics
getCurrent: () => RuntimeEnvironmentStatus | undefined
updateState: (status: RuntimeEnvironmentStatus) => boolean
afterPublish?: (status: RuntimeEnvironmentStatus) => void
}): void {
diagnosticsGeneration.mergePushedRuntimeEnvironmentDiagnostics({
environmentId: args.environmentId,
transportGeneration: args.transportGeneration,
diagnostics: args.diagnostics,
current: args.getCurrent(),
publish: (status) => {
if (args.updateState(status)) {
args.afterPublish?.(status)
}
}
})
}
export function applyRuntimeEnvironmentStatusOverlay(args: {
environmentId: string
status: RuntimeEnvironmentStatus
setState: (
updater: (state: Map<string, RuntimeEnvironmentStatus>) => Map<string, RuntimeEnvironmentStatus>
) => void
}): boolean {
let updated = false
args.setState((state) => {
const next = diagnosticsGeneration.updateRuntimeEnvironmentStatusOverlay(
state,
args.environmentId,
args.status
)
updated = next !== state
return next
})
return updated
}
export function createRuntimeEnvironmentDiagnosticsPublisher(args: {
getCurrent: (environmentId: string) => RuntimeEnvironmentStatus | undefined
setState: (
updater: (state: Map<string, RuntimeEnvironmentStatus>) => Map<string, RuntimeEnvironmentStatus>
) => void
afterPublish: (environmentId: string, status: RuntimeEnvironmentStatus) => void
}): (event: {
environmentId: string
transportGeneration: number
diagnostics: RemoteRuntimeSharedConnectionDiagnostics
}) => void {
return (event) =>
publishRuntimeEnvironmentDiagnostics({
...event,
getCurrent: () => args.getCurrent(event.environmentId),
updateState: (status) =>
applyRuntimeEnvironmentStatusOverlay({
environmentId: event.environmentId,
status,
setState: args.setState
}),
afterPublish: (status) => args.afterPublish(event.environmentId, status)
})
}
+10 -13
View File
@@ -18,6 +18,7 @@ import { reconcileCatalogRows } from './repo-identity-reconcile'
import { createRuntimeStatusHydration } from './runtime-status-hydration'
import { refreshRuntimeEnvironmentStatus } from './runtime-status-refresh'
import * as runtimeStatusDiagnostics from './runtime-status-diagnostics-generation'
import * as runtimeStatusDiagnosticsPublish from './runtime-status-diagnostics-publish'
import {
advanceRuntimeEnvironmentConnectionGeneration,
clearRuntimeEnvironmentConnectionGenerations,
@@ -300,20 +301,16 @@ export const createRuntimeStatusSlice: StateCreator<AppState, [], [], RuntimeSta
}
},
publishRuntimeEnvironmentDiagnostics: ({ environmentId, transportGeneration, diagnostics }) => {
// Diagnostics are an overlay, not a replacement status response. Without a complete
// status snapshot there is no runtime identity or graph evidence to which they belong.
runtimeStatusDiagnostics.mergePushedRuntimeEnvironmentDiagnostics({
environmentId,
transportGeneration,
diagnostics,
current: get().runtimeStatusByEnvironmentId.get(environmentId),
publish: (status) =>
set((s) =>
runtimeStatusDiagnostics.updateRuntimeEnvironmentStatusOverlay(s, environmentId, status)
publishRuntimeEnvironmentDiagnostics:
runtimeStatusDiagnosticsPublish.createRuntimeEnvironmentDiagnosticsPublisher({
getCurrent: (environmentId) => get().runtimeStatusByEnvironmentId.get(environmentId),
setState: (updater) =>
set((s) => ({ runtimeStatusByEnvironmentId: updater(s.runtimeStatusByEnvironmentId) })),
afterPublish: (environmentId, status) =>
runtimeStatusRecheck.reconcileRuntimeStatusForSlice(environmentId, status.status, get, () =>
getRuntimeEnvironmentConnectionGeneration(environmentId)
)
})
},
}),
clearRuntimeEnvironmentStatus: (environmentId) => {
runtimeStatusRecheck.cancelRuntimeStatusRecheck(environmentId)