77, 'path' => $fixture]]; $config = ['enabled' => true, 'python' => $python, 'timeout_seconds' => 20, 'threads' => 1, 'detection_limit' => 640, 'max_text_bytes' => 4096]; $before = glob(sys_get_temp_dir() . '/clinical-ocr-*') ?: []; $result = ClinicalImageTextService::read($sources, dirname($fixture), microtime(true) + 20, null, $config); if ($result['status'] !== 'completed' || $result['images'][0]['index'] !== 77 || !$result['images'][0]['lines']) { throw new RuntimeException('synthetic OCR bridge unavailable; safe status=' . $result['status'] . ' reason=' . ($result['reason'] ?? 'none')); } // Deliberately persist/print neither recognized values nor boxes. $lines = count($result['images'][0]['lines']); unset($result); $started = microtime(true); $timeout = ClinicalImageTextService::read($sources, dirname($fixture), microtime(true) + 0.06, null, $config); if (microtime(true) - $started > 1.0 || ($timeout['reason'] ?? '') !== 'deadline') throw new RuntimeException('real child deadline was not bounded'); $checks = 0; $cancel = ClinicalImageTextService::read($sources, dirname($fixture), microtime(true) + 20, static function () use (&$checks): bool { return ++$checks > 1; }, $config); if (($cancel['reason'] ?? '') !== 'cancelled') throw new RuntimeException('real child cancellation not observed'); $after = glob(sys_get_temp_dir() . '/clinical-ocr-*') ?: []; if (array_diff($after, $before)) throw new RuntimeException('new request-private OCR files remain'); echo 'Local synthetic OCR bridge: processed=1, lines=' . $lines . ", deadline+cancel+cleanup OK; raw values/boxes saved=0\n";