diff --git a/src/mount/relayfile-integration-preflight.test.ts b/src/mount/relayfile-integration-preflight.test.ts index eb66a3d6..d72d626b 100644 --- a/src/mount/relayfile-integration-preflight.test.ts +++ b/src/mount/relayfile-integration-preflight.test.ts @@ -131,4 +131,53 @@ describe('Relayfile integration preflight', () => { expect(terminal.confirm).not.toHaveBeenCalled() expect(relayfile.connect).not.toHaveBeenCalled() }) + + it('directs completed-but-degraded integrations to an authorized repair instead of waiting', async () => { + const relayfile = connections(async () => ({ + ready: false, + state: 'degraded', + initialSyncState: 'complete', + })) + const terminal = io() + + await expect(ensureFactoryIntegrations({ + connections: relayfile, + providers: ['github'], + workspaceId: 'rw_test', + interactive: false, + dryRun: true, + io: terminal, + })).rejects.toThrow( + /degraded after its initial sync completed \(degraded, complete\).*workspace owner.*repair or reconnect github/u, + ) + expect(relayfile.connect).not.toHaveBeenCalled() + expect(relayfile.waitForConnection).not.toHaveBeenCalled() + }) + + it('classifies a degraded completed integration by its normalized state, echoing the reported values', async () => { + const relayfile = connections(async () => ({ + ready: false, + state: ' DeGraded ', + initialSyncState: '\tComplete ', + })) + const terminal = io() + + // Only `.trim().toLowerCase()` routes this to the repair branch; without it + // the provider falls back to "wait for its initial sync", which is the + // advice #203 is about. The details string deliberately echoes the values + // as the provider reported them, so the operator can match them to what + // the dashboard shows -- normalization decides the branch, not the text. + await expect(ensureFactoryIntegrations({ + connections: relayfile, + providers: ['github'], + workspaceId: 'rw_test', + interactive: false, + dryRun: true, + io: terminal, + })).rejects.toThrow( + /degraded after its initial sync completed \( DeGraded ,\s+Complete \).*workspace owner.*repair or reconnect github/u, + ) + expect(relayfile.connect).not.toHaveBeenCalled() + expect(relayfile.waitForConnection).not.toHaveBeenCalled() + }) }) diff --git a/src/mount/relayfile-integration-preflight.ts b/src/mount/relayfile-integration-preflight.ts index e3ad5c33..c52af375 100644 --- a/src/mount/relayfile-integration-preflight.ts +++ b/src/mount/relayfile-integration-preflight.ts @@ -125,6 +125,13 @@ const notReadyMessage = ( const details = [observation.state, observation.initialSyncState] .filter((value): value is string => Boolean(value)) .join(', ') + const state = observation.state?.trim().toLowerCase() + const initialSyncState = observation.initialSyncState?.trim().toLowerCase() + if (state === 'degraded' && initialSyncState === 'complete') { + return `[factory] ${provider} is connected but degraded after its initial sync completed` + + `${details ? ` (${details})` : ''}; ask an Agent Relay workspace owner to repair or reconnect ` + + `${provider}, then retry.` + } return `[factory] ${provider} is connected but not ready${details ? ` (${details})` : ''}; wait for its initial sync, then retry.` }