test(remote-runtime): pin the 12 hand-kept error-code lists to their callers' policy (#30246)

Each list that decides delivered / undelivered / recoverable / definitive by code now has a
test naming its codes, the message fragments it relies on, and nearby codes it must not
treat the same. Includes the #30146 shape: a client-minted runtime_manually_disconnected
keeps a user's close for replay. Tests only; no production change.
This commit is contained in:
Neil
2026-10-18 00:24:34 -07:00
committed by GitHub
parent 1de30d8235
commit 0d74111ee8
12 changed files with 651 additions and 1 deletions
+61
View File
@@ -0,0 +1,61 @@
import { describe, expect, it, vi } from 'vitest'
import { JIRA_AGENT_ACCESS_RUNTIME_CAPABILITY } from '../../shared/jira-agent-capability'
import { RuntimeClientError } from '../runtime-client'
import { JIRA_WRITE_HANDLERS } from './jira-write'
function clientFailingWrite(failure: Error) {
return vi.fn(async (method: string) => {
if (method === 'status.get') {
return { result: { capabilities: [JIRA_AGENT_ACCESS_RUNTIME_CAPABILITY] } }
}
if (method === 'jira.status') {
return { result: { sites: [{ id: 'site-1' }], selectedSiteId: 'site-1' } }
}
throw failure
})
}
async function clearAssigneeAfter(failure: Error): Promise<unknown> {
const handler = JIRA_WRITE_HANDLERS['jira assignee clear']
try {
await handler({
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the handler only calls client.call.
client: { call: clientFailingWrite(failure) } as never,
cwd: '/tmp',
flags: new Map([['key', 'ORCA-1']]),
json: false
})
} catch (error) {
return error
}
throw new Error('expected the write to fail')
}
// Pins which write failures say "may have been applied" (round-2 S5), so a dropped code is deliberate.
describe('Jira write outcome-unknown codes', () => {
it.each([
'runtime_timeout',
'runtime_connection_failed',
'runtime_disconnected',
'runtime_unavailable'
])('reports %s as an unverified write', async (code) => {
await expect(
clearAssigneeAfter(new RuntimeClientError(code, 'failed.'))
).resolves.toMatchObject({ code: 'jira_write_unverified' })
})
it.each([
'remote_runtime_unavailable',
'runtime_manually_disconnected',
'runtime_source_mismatch',
'invalid_argument'
])('passes %s through unchanged', async (code) => {
const failure = new RuntimeClientError(code, 'failed.')
await expect(clearAssigneeAfter(failure)).resolves.toBe(failure)
})
it('passes a non-client error through unchanged', async () => {
const failure = new Error('runtime_timeout')
await expect(clearAssigneeAfter(failure)).resolves.toBe(failure)
})
})
@@ -314,4 +314,19 @@ describe('orchestration mutation recovery', () => {
expect(result.data).not.toHaveProperty('originalCommand')
expect((result.data as { recovery: object }).recovery).not.toHaveProperty('retryCommand')
})
// Pins the outcome-unknown codes (round-2 S5): only these get recovery guidance.
it.each([
['runtime_unavailable', true],
['remote_runtime_unavailable', true],
['runtime_timeout', true],
['invalid_runtime_response', true],
['runtime_manually_disconnected', false],
['remote_runtime_timeout', false],
['runtime_rpc_queue_overloaded', false],
['invalid_argument', false]
])('treats %s as an unknown mutation outcome: %s', (code, unknown) => {
const error = new RuntimeClientError(code, 'failed', { orchestrationRequestId: 'request-1' })
expect(orchestrationMutationRecoveryError(error) !== error).toBe(unknown)
})
})
@@ -0,0 +1,37 @@
import { describe, expect, it } from 'vitest'
import { RemoteRuntimeClientError } from '../../../../shared/remote-runtime-client-error'
import { classifyAutomationHostQueryError } from './automation-host-cache-error'
function classify(error: unknown): { code: string; retryable: boolean } {
const { code, retryable } = classifyAutomationHostQueryError(error, { attempt: 1, now: 0 })
return { code, retryable }
}
// Pins the RPC-code mapping of host query failures (round-2 S5), so a dropped code is deliberate.
describe('classifyAutomationHostQueryError code mapping', () => {
it.each([
['runtime_unavailable', 'authority_unavailable', true],
['remote_runtime_unavailable', 'authority_unavailable', true],
['relay_quota_exceeded', 'authority_unavailable', true],
['timeout', 'timeout', true],
['runtime_timeout', 'timeout', true],
['permission_denied', 'permission_denied', false],
['unauthorized', 'permission_denied', false],
['forbidden', 'permission_denied', false],
['capability_unsupported', 'incompatible', false],
['legacy_read_only', 'incompatible', false],
['invalid_runtime_response', 'invalid_response', false],
['invalid_argument', 'invalid_response', false],
['runtime_manually_disconnected', 'unknown', true],
['runtime_rpc_queue_overloaded', 'unknown', true],
['remote_runtime_busy', 'unknown', true]
])('maps %s to %s (retryable: %s)', (rpcCode, code, retryable) => {
expect(classify(new RemoteRuntimeClientError(rpcCode, 'failed'))).toEqual({ code, retryable })
})
it('reads a code-stripped message token', () => {
expect(
classify(new Error("Error invoking remote method 'x': Error: failed: runtime_timeout"))
).toEqual({ code: 'timeout', retryable: true })
})
})
@@ -524,4 +524,37 @@ describe('structured agent session launch', () => {
expect(transportError).not.toBeInstanceOf(StructuredAgentSessionCreateRefusalError)
})
// Pins the thrown-error half (round-2 S5): a host that flattened the refusal to runtime_error
// still ends it with the token, and client-minted codes never prove nothing was created.
it('reads a definitive token from a flattened runtime_error message', async () => {
mockSupportedCreate(() => {
throw Object.assign(new Error('structured_agent_session_unsupported'), {
code: 'runtime_error'
})
})
const error = await launchStructuredAgentSession(
createStructuredAgentSessionLaunchIntent('workspace-flattened-refusal', 'codex')
).catch((caught: unknown) => caught)
expect(error).toBeInstanceOf(StructuredAgentSessionCreateRefusalError)
expect(error).toMatchObject({ code: 'structured_agent_session_unsupported' })
})
it.each([
'runtime_manually_disconnected',
'runtime_rpc_queue_overloaded',
'runtime_unavailable',
'remote_runtime_unavailable',
'method_not_supported'
])('keeps a thrown %s outcome unknown', async (code) => {
mockSupportedCreate(() => {
throw Object.assign(new Error('failed'), { code })
})
const error = await launchStructuredAgentSession(
createStructuredAgentSessionLaunchIntent(`workspace-client-${code}`, 'codex')
).catch((caught: unknown) => caught)
expect(error).not.toBeInstanceOf(StructuredAgentSessionCreateRefusalError)
})
})
@@ -0,0 +1,79 @@
import { describe, expect, it, vi } from 'vitest'
import { RemoteRuntimeClientError } from '../../../shared/remote-runtime-client-error'
import type { WebRuntimeBrowserCreationContext } from './web-runtime-browser-creation-context'
import { prepareWebRuntimeBrowserCreationFailure } from './web-runtime-browser-creation-failure'
vi.mock('../store', () => ({ useAppStore: { getState: vi.fn(), setState: vi.fn() } }))
function failedCreateContext(): WebRuntimeBrowserCreationContext {
return {
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the failure path reads only worktreeId and the group fields, which are absent here.
args: { worktreeId: 'repo::/w' } as never,
environmentId: 'env-1',
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the prepare step never reads the intent owner.
intentOwner: {} as never,
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the prepare step never calls the environment.
callEnvironment: vi.fn() as never,
shouldFocusOnCreate: false,
shouldSelectWorktree: false,
provisionalPageId: 'provisional-page',
hostSupportsKnownPageId: true,
expectsClientHosting: false,
unsubscribeFocusGuard: vi.fn(),
guardedPageId: 'provisional-page',
createdPageId: null,
createAttempted: true,
staged: null
}
}
function prepare(error: unknown): { cleanupPageId: string | null; createOutcomeUnknown: boolean } {
const { cleanupPageId, createOutcomeUnknown } = prepareWebRuntimeBrowserCreationFailure(
failedCreateContext(),
error
)
return { cleanupPageId, createOutcomeUnknown }
}
// Pins which create failures prove no page exists (round-2 S5), so a dropped code is deliberate.
describe('prepareWebRuntimeBrowserCreationFailure definitive codes', () => {
it.each([
'browser_error',
'capability_unsupported',
'invalid_argument',
'invalid_params',
'method_not_found',
'runtime_rpc_queue_overloaded',
'selector_ambiguous',
'selector_not_found',
'unauthorized'
])('skips the provisional-page cleanup after %s', (code) => {
expect(prepare(new RemoteRuntimeClientError(code, 'failed'))).toEqual({
cleanupPageId: null,
createOutcomeUnknown: false
})
})
it.each([
'runtime_manually_disconnected',
'runtime_unavailable',
'remote_runtime_unavailable',
'runtime_timeout',
'remote_runtime_busy',
'runtime_error'
])('cleans up the provisional page after %s', (code) => {
expect(prepare(new RemoteRuntimeClientError(code, 'failed'))).toEqual({
cleanupPageId: 'provisional-page',
createOutcomeUnknown: false
})
})
it('reads a definitive code from a code-stripped message token', () => {
expect(
prepare(new Error("Error invoking remote method 'x': Error: failed: method_not_found"))
).toEqual({
cleanupPageId: null,
createOutcomeUnknown: false
})
})
})
@@ -0,0 +1,185 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import type * as TrackingDecisions from './web-session-tabs-sync/tracking-decisions'
import { closeWebRuntimeSessionTab } from './web-runtime-session-tab-lifecycle'
import {
resetWebSessionCloseReplaysForTests,
takeDueWebSessionCloseReplays
} from './web-session-close-replay'
import { resetWebSessionFocusIntentForTests } from './web-session-focus-intent'
import {
isWebSessionCloseIntentPending,
resetWebSessionCloseIntentForTests
} from './web-session-close-intent'
import { ENVIRONMENT_ID, WORKTREE_ID } from './web-runtime-session-test-harness'
import { stubRuntimeEnvironmentBridge } from './runtime-environment-bridge-fixture'
const mocks = vi.hoisted(() => ({
getState: vi.fn(),
setState: vi.fn(),
subscribe: vi.fn(),
setActiveWorktree: vi.fn(),
createBrowserTab: vi.fn(),
closeEmptyGroup: vi.fn(),
moveUnifiedTabToGroup: vi.fn(),
setRemoteBrowserPageHandle: vi.fn(),
focusBrowserTabInWorktree: vi.fn(),
applyWebSessionTabsSnapshot: vi.fn(),
decideWebSessionTabsSnapshot: vi.fn(() => ({ apply: true, settlesHostMirror: true })),
getWebSessionTabsTrackingGeneration: vi.fn(() => 0),
acceptReplayedWebSessionTabsSnapshot: vi.fn(),
resolveHostSessionTabIdForWebSessionTab: vi.fn(),
trackTerminalPaneSplit: vi.fn(),
deliverLaunchPromptToAgentTab: vi.fn(),
seedNativeChatLaunchDraftForAgentTab: vi.fn(),
getRuntimeEnvironmentIdForWorktree: vi.fn(),
hasMaterializedWebRuntimeBrowserPage: vi.fn()
}))
vi.mock('../store', () => ({
useAppStore: {
getState: mocks.getState,
setState: mocks.setState,
subscribe: mocks.subscribe
}
}))
vi.mock('./web-session-tabs-sync/tracking-lifecycle', () => ({
acceptReplayedWebSessionTabsSnapshot: mocks.acceptReplayedWebSessionTabsSnapshot,
getWebSessionTabsTrackingGeneration: mocks.getWebSessionTabsTrackingGeneration
}))
vi.mock('./web-session-tabs-sync/snapshot-api', () => ({
applyWebSessionTabsSnapshot: mocks.applyWebSessionTabsSnapshot
}))
vi.mock('./web-session-tabs-sync/tracking-decisions', async (importOriginal) => ({
...(await importOriginal<typeof TrackingDecisions>()),
decideWebSessionTabsSnapshot: mocks.decideWebSessionTabsSnapshot
}))
vi.mock('./web-session-tabs-sync/store-patch', () => ({
applyWebSessionTabsStorePatch: (buildPatch: (state: unknown) => unknown) => {
mocks.setState(buildPatch)
// The production caller invokes the returned settle receipt.
return () => {}
}
}))
vi.mock('./web-session-tabs-sync/tracking-mappings', () => ({
resolveHostSessionTabIdForWebSessionTab: mocks.resolveHostSessionTabIdForWebSessionTab
}))
vi.mock('@/lib/feature-education-telemetry', () => ({
trackTerminalPaneSplit: mocks.trackTerminalPaneSplit
}))
vi.mock('@/lib/worktree-runtime-owner', () => ({
getRuntimeEnvironmentIdForWorktree: mocks.getRuntimeEnvironmentIdForWorktree
}))
vi.mock('@/lib/agent-launch-prompt-delivery', () => ({
deliverLaunchPromptToAgentTab: mocks.deliverLaunchPromptToAgentTab,
seedNativeChatLaunchDraftForAgentTab: mocks.seedNativeChatLaunchDraftForAgentTab
}))
vi.mock('./web-runtime-browser-materialization', () => ({
hasMaterializedWebRuntimeBrowserPage: mocks.hasMaterializedWebRuntimeBrowserPage
}))
afterEach(() => {
resetWebSessionCloseIntentForTests()
resetWebSessionCloseReplaysForTests()
})
const OWNER = { environmentId: ENVIRONMENT_ID }
async function closeAfter(failure: unknown, rejects = false): Promise<boolean> {
const runtimeCall = vi.fn()
if (rejects) {
runtimeCall.mockRejectedValueOnce(failure)
} else {
runtimeCall.mockResolvedValueOnce(failure)
}
runtimeCall.mockResolvedValue({ id: 'close', ok: true, result: { closed: true } })
stubRuntimeEnvironmentBridge({ call: runtimeCall })
await expect(
closeWebRuntimeSessionTab({
worktreeId: WORKTREE_ID,
tabId: 'local-browser-unified',
reason: 'user'
})
).resolves.toBe('failed')
const held = isWebSessionCloseIntentPending(
OWNER,
WORKTREE_ID,
'host-browser-unified',
Date.now() + 60_000
)
const replayQueued =
takeDueWebSessionCloseReplays(OWNER, WORKTREE_ID, new Set(['host-browser-unified'])).length > 0
expect(replayQueued).toBe(held)
return held
}
function envelope(code: string): unknown {
return { id: 'close', ok: false, error: { code, message: 'failed' } }
}
// Pins which close failures keep the user's close for replay (round-2 S5), so a dropped code is deliberate.
describe('user close: which failures keep the intent', () => {
beforeEach(() => {
vi.stubGlobal('__ORCA_WEB_CLIENT__', true)
mocks.getState.mockReturnValue({
settings: {
activeRuntimeEnvironmentId: ENVIRONMENT_ID
},
tabsByWorktree: {},
terminalLayoutsByTabId: {},
activeTabIdByWorktree: {},
activeGroupIdByWorktree: {},
setActiveWorktree: mocks.setActiveWorktree
})
mocks.resolveHostSessionTabIdForWebSessionTab.mockImplementation(
(_state, args: { tabId: string }) =>
args.tabId === 'local-browser-unified' ? 'host-browser-unified' : null
)
// Store patches must run their updater so snapshot reconciliation is observable.
mocks.setState.mockImplementation((updater: (state: unknown) => unknown) => {
updater({
state: 'before',
activeWorktreeId: WORKTREE_ID
})
})
mocks.applyWebSessionTabsSnapshot.mockReturnValue({ state: 'after' })
})
afterEach(() => {
resetWebSessionFocusIntentForTests()
vi.unstubAllGlobals()
vi.clearAllMocks()
})
it.each([
'runtime_manually_disconnected',
'runtime_unavailable',
'remote_runtime_unavailable',
'runtime_timeout',
'remote_runtime_timeout'
])('keeps the close when the answer is %s', async (code) => {
expect(await closeAfter(envelope(code))).toBe(true)
})
// #30146: the web client mints this as a bare Error; it must never drop the close.
it('keeps the close when the client itself refuses with runtime_manually_disconnected', async () => {
expect(await closeAfter(new Error('runtime_manually_disconnected'), true)).toBe(true)
})
it('keeps the close on any thrown transport failure', async () => {
expect(await closeAfter(new Error('socket hang up'), true)).toBe(true)
})
it.each([
'invalid_argument',
'runtime_rpc_queue_overloaded',
'ssh_user_disconnected',
'conflict'
])('drops the close when the answer is %s', async (code) => {
expect(await closeAfter(envelope(code))).toBe(false)
})
})
@@ -0,0 +1,42 @@
import { describe, expect, it } from 'vitest'
import { isStableAdoptionFailure } from './web-session-terminal-orphan-recovery-adoption'
function failure(code: string, message = 'refused'): unknown {
return { id: 'adopt', ok: false, error: { code, message } }
}
// Pins which adoption failures stop retrying (round-2 S5), so a dropped code is deliberate.
describe('isStableAdoptionFailure', () => {
it.each(['method_not_found', 'capability_unsupported', 'invalid_runtime_response'])(
'treats %s as stable',
(code) => {
expect(isStableAdoptionFailure(failure(code))).toBe(true)
}
)
it.each([
'remote_runtime_unavailable',
'remote_runtime_busy',
'runtime_rpc_queue_overloaded',
'runtime_timeout',
'runtime_unavailable',
'reconnecting',
'timeout',
'runtime_manually_disconnected',
'terminal_not_found'
])('keeps retrying after %s', (code) => {
expect(isStableAdoptionFailure(failure(code))).toBe(false)
})
it('keeps retrying a code-stripped connection failure even if it names a stable code', () => {
expect(
isStableAdoptionFailure(
new Error('Could not connect to the remote Orca runtime: method_not_found')
)
).toBe(false)
})
it('reads a stable code from a thrown error message token', () => {
expect(isStableAdoptionFailure(new Error('Adoption failed: capability_unsupported'))).toBe(true)
})
})
@@ -0,0 +1,68 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { RemoteRuntimeClientError } from '../../../shared/remote-runtime-client-error'
import { isWebHostUnreachableAtStartup } from './startup-web-host-unreachable'
vi.mock('sonner', () => ({ toast: vi.fn() }))
function stubWindow(webClient: boolean, snapshots: unknown[]): void {
vi.stubGlobal('window', {
__ORCA_WEB_CLIENT__: webClient,
api: { runtimeEnvironments: { getStatusSnapshots: vi.fn(async () => snapshots) } }
})
}
// Pins which boot failures read as "host unreachable" (round-2 S5), so a dropped code is deliberate.
describe('isWebHostUnreachableAtStartup', () => {
beforeEach(() => {
stubWindow(true, [])
})
afterEach(() => {
vi.unstubAllGlobals()
})
it.each([
'remote_runtime_unavailable',
'remote_runtime_busy',
'runtime_rpc_queue_overloaded',
'runtime_timeout',
'runtime_unavailable',
'reconnecting',
'timeout'
])('treats %s as unreachable while the transport is down', async (code) => {
await expect(
isWebHostUnreachableAtStartup(new RemoteRuntimeClientError(code, 'failed'))
).resolves.toBe(true)
})
it.each([
'Timed out while connecting to the remote Orca runtime.',
'Remote Orca runtime connection interrupted.',
'Could not connect to the remote Orca runtime.'
])('treats the code-less message "%s" as unreachable', async (message) => {
await expect(isWebHostUnreachableAtStartup(new Error(message))).resolves.toBe(true)
})
it.each(['runtime_manually_disconnected', 'invalid_runtime_response', 'unauthorized'])(
'treats %s as a hydration fault',
async (code) => {
await expect(
isWebHostUnreachableAtStartup(new RemoteRuntimeClientError(code, 'failed'))
).resolves.toBe(false)
}
)
it('treats a connection failure on a ready transport as a hydration fault', async () => {
stubWindow(true, [{ transport: 'ready', retired: false }])
await expect(
isWebHostUnreachableAtStartup(new RemoteRuntimeClientError('runtime_timeout', 'failed'))
).resolves.toBe(false)
})
it('is never true outside the web client', async () => {
stubWindow(false, [])
await expect(
isWebHostUnreachableAtStartup(new RemoteRuntimeClientError('runtime_timeout', 'failed'))
).resolves.toBe(false)
})
})
@@ -0,0 +1,48 @@
import { describe, expect, it } from 'vitest'
import { RemoteRuntimeClientError } from '../../../../../../shared/remote-runtime-client-error'
import { RuntimeRpcCallQueueOverloadError } from '../../../../../../shared/runtime-rpc-call-queue'
import { isWorktreeRemovalReplyLost } from './host-worktree-removal-state'
// Pins which delete failures wait on the host's listing (round-2 S5), so a dropped code is deliberate.
describe('isWorktreeRemovalReplyLost', () => {
it.each([
'remote_runtime_unavailable',
'remote_runtime_busy',
'runtime_timeout',
'runtime_unavailable',
'reconnecting',
'timeout'
])('treats %s as a lost reply', (code) => {
expect(isWorktreeRemovalReplyLost(new RemoteRuntimeClientError(code, 'transport failed'))).toBe(
true
)
})
it('treats a queue overload as never sent', () => {
expect(isWorktreeRemovalReplyLost(new RuntimeRpcCallQueueOverloadError('global'))).toBe(false)
expect(
isWorktreeRemovalReplyLost(
new Error(
"Error invoking remote method 'x': Error: Remote runtime call queue is full; retry after current calls finish."
)
)
).toBe(false)
})
it.each([
'runtime_manually_disconnected',
'invalid_runtime_response',
'unauthorized',
'worktree_not_found'
])('does not treat %s as a lost reply', (code) => {
expect(isWorktreeRemovalReplyLost(new RemoteRuntimeClientError(code, 'refused'))).toBe(false)
})
it.each([
"Error invoking remote method 'x': Error: Request timed out.",
"Error invoking remote method 'x': Error: Remote Orca runtime connection interrupted.",
"Error invoking remote method 'x': Error: Could not connect to the remote Orca runtime."
])('treats the code-stripped message "%s" as a lost reply', (message) => {
expect(isWorktreeRemovalReplyLost(new Error(message))).toBe(true)
})
})
@@ -38,4 +38,19 @@ describe('definitive agent-session create refusals', () => {
)
expect(isDefinitiveAgentSessionCreateRefusal('structured_agent_session_unsupported')).toBe(true)
})
// Pins the RPC half (round-2 S5): transport and client-minted codes never allow a fallback.
it.each([
'runtime_unavailable',
'remote_runtime_unavailable',
'runtime_timeout',
'runtime_manually_disconnected',
'runtime_rpc_queue_overloaded',
'method_not_supported',
'invalid_argument',
null,
undefined
])('does not count %s as definitive', (code) => {
expect(isDefinitiveAgentSessionCreateRefusal(code)).toBe(false)
})
})
@@ -1,5 +1,7 @@
import { describe, expect, it } from 'vitest'
import {
RECOVERABLE_CODES,
RECOVERABLE_MESSAGE_FRAGMENTS,
isRecoverableRemoteRuntimeConnectionError,
isRuntimeRpcQueueOverloadError,
toRemoteRuntimeClientErrorLike
@@ -61,4 +63,54 @@ describe('remote runtime client error classification', () => {
const error = toRemoteRuntimeClientErrorLike(new Error(message))
expect(isRecoverableRemoteRuntimeConnectionError(error)).toBe(true)
})
// Pins the list so a dropped or added code is a deliberate, reviewed change (round-2 S5).
it('pins the recoverable codes and message fragments', () => {
expect([...RECOVERABLE_CODES].toSorted()).toEqual([
'reconnecting',
'remote_runtime_busy',
'remote_runtime_unavailable',
'runtime_rpc_queue_overloaded',
'runtime_timeout',
'runtime_unavailable',
'timeout'
])
expect(RECOVERABLE_MESSAGE_FRAGMENTS).toEqual([
'could not connect to the remote orca runtime',
'remote orca runtime closed the connection',
'remote orca runtime connection closed',
'remote orca runtime is not connected',
'remote runtime call queue is full',
'remote runtime connection closed',
'remote runtime connection wait limit reached',
'remote runtime request limit reached',
'remote runtime subscription limit reached',
'remote runtime subscription memory limit reached',
'remote runtime subscription closed before it started',
'remote terminal stream is not connected',
'timed out waiting for the remote orca runtime'
])
})
it.each([
'runtime_manually_disconnected',
'ssh_user_disconnected',
'remote_runtime_timeout',
'runtime_busy'
])('does not treat client code %s as recoverable', (code) => {
expect(isRecoverableRemoteRuntimeConnectionError({ code, message: 'refused' })).toBe(false)
})
it.each(RECOVERABLE_MESSAGE_FRAGMENTS)(
'recovers a code-stripped message containing %s',
(fragment) => {
expect(
isRecoverableRemoteRuntimeConnectionError(
toRemoteRuntimeClientErrorLike(
new Error(`Error invoking remote method 'x': Error: ${fragment}.`)
)
)
).toBe(true)
}
)
})
@@ -98,6 +98,15 @@ describe('structuredAgentSessionSendEvidence', () => {
]) {
expect(structuredAgentSessionSendEvidence(thrown(rpcCode)).kind).toBe('uncertain')
}
for (const rpcCode of [
'runtime_manually_disconnected',
'runtime_rpc_queue_overloaded',
'remote_runtime_busy',
'forbidden',
'capability_unsupported'
]) {
expect(structuredAgentSessionSendEvidence(thrown(rpcCode)).kind).toBe('uncertain')
}
const thrownRefusal = {
response: { error: { data: { refusal: { code: 'agent_session_journal_unreadable' } } } }
}
@@ -110,8 +119,14 @@ describe('structuredAgentSessionSendEvidence', () => {
).toBe('uncertain')
})
// Pins the full turned-away list (round-2 S5): every other code, client-minted ones included, is uncertain.
it('treats a call the host turned away before running it as never written', () => {
for (const rpcCode of ['method_not_found', 'invalid_argument', 'unauthorized']) {
for (const rpcCode of [
'method_not_found',
'method_not_supported',
'invalid_argument',
'unauthorized'
]) {
expect(structuredAgentSessionSendEvidence(thrown(rpcCode)).kind).toBe('not-recorded')
}
})