diff --git a/sdk/src/query-gsd-tools-runtime.ts b/sdk/src/query-gsd-tools-runtime.ts index 1ca5dfd75..6ff59c513 100644 --- a/sdk/src/query-gsd-tools-runtime.ts +++ b/sdk/src/query-gsd-tools-runtime.ts @@ -34,7 +34,9 @@ export function createGSDToolsRuntime(opts: { timeoutMs: opts.timeoutMs, workstream: opts.workstream, createToolsError: (message, command, args, exitCode, stderr, classification) => - new GSDToolsError(message, command, args, exitCode, stderr, classification ? { classification } : undefined), + new GSDToolsError(message, command, args, exitCode, stderr, { + classification: classification ?? { kind: 'failure' }, + }), }); const nativeDirectAdapter = new QueryNativeDirectAdapter({ diff --git a/sdk/src/query-tools-error-mapper.test.ts b/sdk/src/query-tools-error-mapper.test.ts index c4c0dd0e6..8915e5975 100644 --- a/sdk/src/query-tools-error-mapper.test.ts +++ b/sdk/src/query-tools-error-mapper.test.ts @@ -14,8 +14,8 @@ describe('query tools error mapper', () => { expect(err.classification).toEqual({ kind: 'timeout', timeoutMs: 1234 }); }); - it('does not attach timeout classification for non-timeout failures', () => { + it('attaches failure classification for non-timeout failures', () => { const err = toGSDToolsError('state', ['load'], new Error('boom')); - expect(err.classification).toBeUndefined(); + expect(err.classification).toEqual({ kind: 'failure' }); }); }); diff --git a/sdk/src/query-tools-error-mapper.ts b/sdk/src/query-tools-error-mapper.ts index 44898ed03..357af2fe4 100644 --- a/sdk/src/query-tools-error-mapper.ts +++ b/sdk/src/query-tools-error-mapper.ts @@ -1,6 +1,6 @@ import { GSDError, exitCodeFor } from './errors.js'; import { GSDToolsError } from './gsd-tools-error.js'; -import { isTimeoutMessage, errorMessage, parseTimeoutMs } from './query-failure-classification.js'; +import { errorMessage, toFailureSignal } from './query-failure-classification.js'; /** * Module owning projection of internal errors to GSDToolsError contract. @@ -18,6 +18,11 @@ export function toGSDToolsError(command: string, args: string[], err: unknown): } const msg = errorMessage(err); + const signal = toFailureSignal(err); + const classification = signal.kind === 'timeout' + ? { kind: 'timeout' as const, timeoutMs: signal.timeoutMs } + : { kind: 'failure' as const }; + return new GSDToolsError( msg, command, @@ -25,14 +30,7 @@ export function toGSDToolsError(command: string, args: string[], err: unknown): 1, '', err instanceof Error - ? { - cause: err, - ...(isTimeoutMessage(msg) - ? { classification: { kind: 'timeout' as const, timeoutMs: parseTimeoutMs(msg) } } - : undefined), - } - : (isTimeoutMessage(msg) - ? { classification: { kind: 'timeout' as const, timeoutMs: parseTimeoutMs(msg) } } - : undefined), + ? { cause: err, classification } + : { classification }, ); } diff --git a/sdk/src/query/query-dispatch-error-mapper.test.ts b/sdk/src/query/query-dispatch-error-mapper.test.ts index 0fa140f89..24a47c0cf 100644 --- a/sdk/src/query/query-dispatch-error-mapper.test.ts +++ b/sdk/src/query/query-dispatch-error-mapper.test.ts @@ -37,6 +37,17 @@ describe('query dispatch error mapper', () => { expect(err.details).toMatchObject({ timeout_ms: 1234 }); }); + it('maps typed failure classification from GSDToolsError', () => { + const err = mapNativeDispatchError( + new GSDToolsError('boom', 'state', ['load'], 1, '', { + classification: { kind: 'failure' }, + }), + 'state.load', + [], + ); + expect(err.kind).toBe('native_failure'); + }); + it('maps fallback errors', () => { const err = mapFallbackDispatchError(new Error('spawn ENOENT'), 'state', ['load']); expect(err.kind).toBe('fallback_failure');