diff --git a/src/shared/timer-delay.test.ts b/src/shared/timer-delay.test.ts index 23171a60e99..7f94b33a655 100644 --- a/src/shared/timer-delay.test.ts +++ b/src/shared/timer-delay.test.ts @@ -33,17 +33,30 @@ describe('timer delay policy', () => { expect(parsePositiveSafeIntegerText(raw)).toBe(expected) }) - it.each(['', '0', '-1', '1.5', '.1', '1e-1', '9007199254740991.1', '9007199254740992'])( - 'rejects inexact or unsafe integer text %s', - (raw) => { - expect(parsePositiveSafeIntegerText(raw)).toBeNull() - } - ) + it.each([ + '', + '0', + '-1', + '1.5', + '.1', + '1e-1', + '1.0000000000000000001', + '+1.0000000000000000001', + '9007199254740991.1', + '9007199254740992' + ])('rejects inexact or unsafe integer text %s', (raw) => { + expect(parsePositiveSafeIntegerText(raw)).toBeNull() + }) + // Values the CLI's own Number() coercion accepts must parse to the same + // budget here, or the caller's timer expires before the CLI's does. it.each([ ['+1000', 1_000], ['1000.0', 1_000], - ['1e3', 1_000] + ['1e3', 1_000], + ['1.0000000000000000001', 1], + ['+1.0000000000000000001', 1], + ['600000.000000000000001', 600_000] ])('parses CLI-compatible positive integer text %s', (raw, expected) => { expect(parsePositiveSafeIntegerNumericText(raw)).toBe(expected) }) diff --git a/src/shared/timer-delay.ts b/src/shared/timer-delay.ts index 99172b99f45..5f57bb4c10e 100644 --- a/src/shared/timer-delay.ts +++ b/src/shared/timer-delay.ts @@ -19,6 +19,12 @@ export function parsePositiveSafeIntegerText(raw: string): number | null { return exactValue === BigInt(value) ? value : null } +// Why: mirrors the CLI's own `Number()` coercion for generic `--timeout-ms` +// flags (cli/flags.ts getOptionalPositiveIntegerFlag). Text that coerces to an +// exact integer — `1000.0`, `600000.000000000000001` — is the budget the CLI +// will actually wait on, so rejecting it here would leave the caller's timer +// shorter than the CLI's and cut the request short. Callers that need exact +// text (orchestration ask) use parsePositiveSafeIntegerText instead. export function parsePositiveSafeIntegerNumericText(raw: string): number | null { const value = Number(raw) return Number.isSafeInteger(value) && value > 0 ? value : null