$deadlineTestNs + 500000000, 'timeout_ms' => 90000]; deadlineExpect($cap->invokeArgs(null, [&$options]) && $options['timeout_ms'] === 500, 'First retry uses only remaining request budget'); $deadlineTestNs += 400000000; deadlineExpect($cap->invokeArgs(null, [&$options]) && $options['timeout_ms'] === 100, 'Compatibility retry cannot reset elapsed budget'); $options['timeout_ms'] = 10; deadlineExpect($cap->invokeArgs(null, [&$options]) && $options['timeout_ms'] === 10, 'Shorter attempt timeout is preserved'); $deadlineTestNs += 100000000; $timeouts = 0; $options['on_timeout'] = static function (string $task) use (&$timeouts): void { ++$timeouts; }; deadlineExpect(!$cap->invokeArgs(null, [&$options]) && $timeouts === 1, 'Expiration notifies timeout without fabricating a task'); $blocking = (new ReflectionMethod(DifyChatService::class, 'sendRequest'))->invoke(null, 'http://invalid.invalid/never-connect', [], 'synthetic', 90, $options); deadlineExpect($blocking['errno'] === CURLE_OPERATION_TIMEDOUT && $blocking['http_code'] === 0, 'Expired blocking attempt performs no network call'); $deltas = 0; $streaming = (new ReflectionMethod(DifyChatService::class, 'sendStreamRequest'))->invoke(null, 'dify', 'http://invalid.invalid/never-connect', [], 'synthetic', 90, static function () use (&$deltas): void { ++$deltas; }, null, $options); deadlineExpect($streaming['errno'] === CURLE_OPERATION_TIMEDOUT && $deltas === 0, 'Expired streaming attempt performs no network or delta'); $clinical = (new ReflectionMethod(DifyChatService::class, 'requiredClinicalChat'))->invoke(null, 'qwen', [], 'synthetic', 'synthetic-user', [['type' => 'image', 'url' => 'http://invalid.invalid/never-upload']], $options, null, null, 3, 90); deadlineExpect(($clinical['error_code'] ?? '') === 'UPSTREAM_TIMEOUT', 'Expired shared request is refused before file validation, upload, or model work'); foreach ([[], ['timeout_ms' => 1000], ['request_deadline_ns' => 0]] as $unbounded) { $copy = $unbounded; deadlineExpect($cap->invokeArgs(null, [&$unbounded]) && $copy === $unbounded, 'Existing stop cleanup and unbudgeted callers stay unchanged'); } echo "Dify monotonic request budget across compatibility attempts: {$checks} checks OK\n"; }