0]; } function curl_setopt_array(\stdClass $handle, array $options): bool { $handle->options = $options; $handle->url = $options[CURLOPT_URL]; return true; } function curl_exec(\stdClass $handle): string|bool { if (str_ends_with($handle->url, '/stop')) { \stopTimingExpect(!$GLOBALS['stopTimingClosed'], 'actual stop I/O precedes generation handle close'); ++$GLOBALS['stopTimingIoCount']; $GLOBALS['stopTimingNow'] += 7; return $GLOBALS['stopTimingMode'] === 'rejected_stop' ? '{"result":"failed"}' : '{"result":"success"}'; } $header = $handle->options[CURLOPT_HEADERFUNCTION]; $write = $handle->options[CURLOPT_WRITEFUNCTION]; $progressOption = defined('CURLOPT_XFERINFOFUNCTION') ? CURLOPT_XFERINFOFUNCTION : CURLOPT_PROGRESSFUNCTION; $progress = $handle->options[$progressOption]; $GLOBALS['stopTimingNow'] += 5; $header($handle, "HTTP/1.1 200 OK\r\n"); $GLOBALS['stopTimingNow'] += 5; if ($write($handle, "data: {\"event\":\"workflow_started\",\"task_id\":\"private-numeric-task\"}\n\n") === 0) { $handle->errno = CURLE_WRITE_ERROR; return false; } if ($GLOBALS['stopTimingMode'] === 'finished_deadline') { $GLOBALS['stopTimingNow'] += 10; $write($handle, "data: {\"event\":\"message_end\"}\n\n"); $GLOBALS['stopTimingNow'] += 5000; \stopTimingExpect($progress($handle, 0, 0, 1, 1) !== 0, 'completed message still wins its deadline race'); $handle->errno = CURLE_ABORTED_BY_CALLBACK; return false; } if ($GLOBALS['stopTimingMode'] === 'timeout') { $GLOBALS['stopTimingNow'] += 10; $handle->errno = CURLE_OPERATION_TIMEDOUT; return false; } if ($GLOBALS['stopTimingMode'] === 'validation') { $GLOBALS['stopTimingNow'] += 10; $write($handle, "data: {\"event\":\"message\",\"answer\":\"private-clinical-content\"}\n\n"); } else { $GLOBALS['stopTimingCancelled'] = true; } for ($index = 0; $index < 4; ++$index) { $GLOBALS['stopTimingNow'] += 10; if ($progress($handle, 0, 0, 1, 1) !== 0) { $handle->errno = CURLE_ABORTED_BY_CALLBACK; return false; } } if ($GLOBALS['stopTimingMode'] === 'local_abort') { $GLOBALS['stopTimingNow'] += 2600; \stopTimingExpect($progress($handle, 0, 0, 1, 1) !== 0, 'original absolute drain budget still aborts'); $handle->errno = CURLE_ABORTED_BY_CALLBACK; return false; } $GLOBALS['stopTimingNow'] += 10; $write($handle, "data: {\"event\":\"workflow_finished\",\"task_id\":\"private-numeric-task\",\"data\":{\"status\":\"cancelled\",\"error\":\"private-provider-error\"}}\n\n"); $GLOBALS['stopTimingNow'] += 10; $write($handle, "data: {\"event\":\"message_end\"}\n\n"); $GLOBALS['stopTimingNow'] += 10; return true; } function curl_errno(\stdClass $handle): int { return $handle->errno; } function curl_getinfo(\stdClass $handle, int $option): int|float { return $option === CURLINFO_HTTP_CODE ? 200 : 0.001; } function curl_close(\stdClass $handle): void { if (!str_ends_with($handle->url, '/stop')) { $GLOBALS['stopTimingClosed'] = true; ++$GLOBALS['stopTimingNow']; } } } namespace { require dirname(__DIR__) . '/vendor/autoload.php'; use app\common\service\DifyChatService; use app\common\service\DifyStreamTiming; function stopTimingExpect(bool $ok, string $message): void { if (!$ok) throw new RuntimeException($message); } $send = (new ReflectionClass(DifyChatService::class))->getMethod('sendStreamRequest'); $run = static function (string $mode) use ($send): array { $GLOBALS['stopTimingNow'] = 1000; $GLOBALS['stopTimingMode'] = $mode; $GLOBALS['stopTimingCancelled'] = false; $GLOBALS['stopTimingClosed'] = false; $GLOBALS['stopTimingIoCount'] = 0; $snapshot = []; $coordinatorCalls = 0; $accepted = false; $delivered = []; $terminals = []; $result = $send->invoke(null, 'dify', 'https://private-numeric.invalid/chat-messages', ['user' => 'private-numeric-user', 'query' => 'private-clinical-prompt'], 'private-api-key', 5, static function (string $delta) use (&$delivered, $mode): bool { if ($mode === 'validation') { $GLOBALS['stopTimingCancelled'] = true; return false; } $delivered[] = $delta; return true; }, static fn (): bool => $GLOBALS['stopTimingCancelled'], [ 'on_task' => static function () use ($mode): void { if ($mode === 'callback_error') throw new RuntimeException('private-observer-error'); }, 'on_cancel_task' => static function (string $task, callable $stop) use (&$coordinatorCalls, &$accepted, $mode): array { ++$coordinatorCalls; if ($mode === 'peer_accepted') return ['accepted' => true]; // Pending lease polls must not become fictitious HTTP stop attempts. if ($coordinatorCalls < 3 && $mode !== 'callback_error' && $mode !== 'timeout') return ['accepted' => false]; if (!$accepted && $GLOBALS['stopTimingIoCount'] === 0) $accepted = $stop(); return ['accepted' => $accepted]; }, 'on_terminal' => static function (string $task, string $status) use (&$terminals): void { $terminals[] = $status; }, 'on_upstream_timing' => static function (DifyStreamTiming $timing) use (&$snapshot): void { $snapshot = $timing->snapshot(); }, ]); $encoded = json_encode($snapshot); stopTimingExpect($GLOBALS['stopTimingClosed'] && isset($snapshot['transport_closed_ms']), 'timing is exported after handle close'); stopTimingExpect(!str_contains($encoded, 'private-'), 'transport telemetry leaks no task, URL, clinical, key or observer data'); return compact('result', 'snapshot', 'coordinatorCalls', 'delivered', 'terminals'); }; $test = $run('cancelled'); $timing = $test['snapshot']; stopTimingExpect($test['coordinatorCalls'] > 3 && $GLOBALS['stopTimingIoCount'] === 1 && $timing['stop_io_attempt_count'] === 1 && $timing['stop_io_completed_count'] === 1 && $timing['stop_io_accepted_count'] === 1, 'only actual performStop I/O increments counters'); stopTimingExpect($timing['interruption_trigger'] === 'abort_signal' && $timing['stop_accepted_source'] === 'local_io' && $timing['workflow_terminal_status'] === 'stopped' && $test['terminals'] === ['stopped'], 'real abort and terminal gates expose fixed safe enums'); $sequence = array_map(static fn (string $key): int => $timing[$key], ['interruption_detected_ms', 'stop_io_begin_ms', 'stop_io_end_ms', 'stop_accepted_ms', 'workflow_terminal_ms', 'natural_eof_ms', 'transport_closed_ms']); $ordered = $sequence; sort($ordered); stopTimingExpect($sequence === $ordered && $timing['stop_io_end_ms'] - $timing['stop_io_begin_ms'] === 7 && $timing['transport_exit'] === 'natural_eof' && $test['delivered'] === [], 'stop I/O, accepted, terminal, natural EOF and close stay distinct'); $test = $run('peer_accepted'); $timing = $test['snapshot']; stopTimingExpect($GLOBALS['stopTimingIoCount'] === 0 && !isset($timing['stop_io_attempt_count']) && $timing['stop_accepted_source'] === 'coordinator' && isset($timing['stop_accepted_ms']), 'peer acceptance never fabricates local stop I/O'); $test = $run('rejected_stop'); $timing = $test['snapshot']; stopTimingExpect($timing['stop_io_attempt_count'] === 1 && $timing['stop_io_completed_count'] === 1 && !isset($timing['stop_accepted_ms']) && !isset($timing['stop_io_accepted_count']), 'failed stop response is completed I/O without accepted proof'); $test = $run('local_abort'); $timing = $test['snapshot']; stopTimingExpect($timing['transport_exit'] === 'local_abort' && !isset($timing['natural_eof_ms']) && !isset($timing['workflow_terminal_ms']) && $timing['stop_io_attempt_count'] === 1 && $test['result']['errno'] === CURLE_ABORTED_BY_CALLBACK, 'budget exit closes locally without inventing natural EOF or workflow terminal'); $test = $run('validation'); stopTimingExpect($test['snapshot']['interruption_trigger'] === 'abort_signal' && $test['delivered'] === [] && $test['result']['client_aborted'] && !$test['result']['callback_error'], 'validation-driven abort is labelled as signal, not doctor cancellation'); $test = $run('callback_error'); stopTimingExpect($test['snapshot']['interruption_trigger'] === 'callback_error' && $test['result']['callback_error'] && $test['snapshot']['transport_exit'] === 'local_abort' && $test['delivered'] === [] && $GLOBALS['stopTimingIoCount'] === 1, 'observer exception remains fail-closed and stops the known task'); $test = $run('timeout'); stopTimingExpect($test['snapshot']['interruption_trigger'] === 'timeout' && $test['result']['timed_out'] && $test['snapshot']['transport_exit'] === 'timeout' && !isset($test['snapshot']['natural_eof_ms']) && $GLOBALS['stopTimingIoCount'] === 1, 'hard cURL timeout preserves timeout semantics and real cleanup timing'); $test = $run('finished_deadline'); stopTimingExpect($test['result']['finished'] && $test['result']['errno'] === 0 && !$test['result']['timed_out'] && $test['snapshot']['transport_exit'] === 'local_abort' && !isset($test['snapshot']['natural_eof_ms']) && !isset($test['snapshot']['interruption_detected_ms']) && $GLOBALS['stopTimingIoCount'] === 0, 'deadline success normalization never fabricates natural EOF or stop I/O'); echo "Offline actual stop I/O / peer lease / terminal gate / EOF vs local abort timing: OK\n"; }