json_encode($value, JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR); $wire = static fn (bool $continuation = false): array => ['protocol' => 'dify', 'body_sha256' => hash('sha256', 'private-body'), 'body_bytes' => 12, 'query_sha256' => hash('sha256', 'private-query'), 'query_bytes' => 13, 'inputs_sha256' => hash('sha256', '{}'), 'inputs_bytes' => 2, 'report_continuation_query' => $continuation]; $record = static function (string $task, string $run, int $generation, string $status = 'stopped'): array { return ['upstream' => ['task_id' => $task, 'workflow_run_id' => $run, 'profile' => 'qwen', 'user' => 'private-user', 'generation' => $generation], 'producer_terminal_status' => 'stopped', 'producer_terminal_observed_at' => 10.0, 'persisted_run_status' => $status, 'persisted_run_observed_at' => 12.0, 'persisted_terminal_confirmed' => $status !== 'running', 'upstream_terminal_confirmed' => $status !== 'running', 'upstream_stop_confirmed' => true, 'stop_accepted_at' => 9.0, 'transfer_closed' => true, 'transfer_closed_at' => 11.0, 'verification_attempts' => 1, 'verification_started_at' => 11.0, 'generation_verification_elapsed_ms' => 20, 'lifecycle_conflict' => $status !== 'stopped', 'run_status_observations' => [['status' => $status, 'observed_at' => 12.0, 'within_budget' => true]]]; }; $finishState = static fn (int $pending, bool $terminal): array => ['transport_closed' => true, 'upstream_terminal_confirmed' => $terminal, 'upstream_stop_confirmed' => true, 'cancel_requested' => false, 'timeout_reached' => false, 'lifecycle_conflict' => $pending > 0, 'upstream_pending_task_count' => $pending]; $make = static function () use ($base, &$number): array { $uuid = sprintf('d5678901-1234-4234-8234-%012d', ++$number); $control = $base . '/control-' . $number . '.json'; file_put_contents($control, '{}'); return [new PrivateTcmR26WireAudit($base . '/audits', $uuid, 'independent_case_' . $number, 'qwen', $control), $control, $base . '/audits/' . hash('sha256', $uuid) . '.private.jsonl']; }; $private = static function (array $summary) use ($expect, $json): void { foreach (['private-task', 'private-run', 'private-user', 'd5678901-', 'private-body', 'private-query'] as $text) $expect(!str_contains($json($summary), $text), 'safe summary excludes raw identity/body sentinel'); }; try { // The preserved real transport contract calls this field transport_exit. // Do not use the helper's own spelling as the expected fixture. foreach (['natural_eof', 'timeout', 'local_abort', 'transport_error', 'exception'] as $exit) { [$a, $path, $auditPath] = $make(); $identity = $a->observe($wire()); $identity('private-task', 'private-run'); $a->transferClosed(1, ['transport_closed_ms' => 5, 'transport_exit' => $exit], 20.0); file_put_contents($path, $json(['completed_generations' => [7 => $record('private-task', 'private-run', 7)]])); $a->captureControl('private-task'); $summary = $a->finish($finishState(0, true)); $expect($summary['persisted'] && $summary['independent_cleanup_confirmed'], 'valid exact private archive certifies only terminal generation'); $expect($summary['generations'][0]['transfer_exit'] === $exit, 'real transport exit enum retained ' . $exit); $rows = array_map(static fn (string $line): array => json_decode($line, true, 64, JSON_THROW_ON_ERROR), file($auditPath, FILE_IGNORE_NEW_LINES)); $closed = array_values(array_filter($rows, static fn (array $row): bool => $row['event'] === 'generation_transfer_closed')); $expect($closed[0]['transfer_exit'] === $exit, 'private closure row retains real transport exit enum ' . $exit); $expect(hash_file('sha256', $auditPath) === $summary['audit_sha256'], 'durable digest includes exact closure and footer'); $private($summary); $observations[] = ['label' => 'transport_exit_' . $exit, 'expected' => $exit, 'actual' => $summary['generations'][0]['transfer_exit']]; } [$a, $path, $auditPath] = $make(); $first = $a->observe($wire()); $second = $a->observe($wire(true)); $second('private-task-2', 'private-run-2'); $first('private-task-1'); $first('private-task-1', 'private-run-1'); $a->transferClosed(1, ['transport_closed_ms' => 2, 'transport_exit' => 'natural_eof'], 10.0); $a->transferClosed(2, ['transport_closed_ms' => 3, 'transport_exit' => 'natural_eof'], 30.0); file_put_contents($path, $json($record('private-task-2', 'private-run-2', 9, 'running') + ['completed_generations' => [8 => $record('private-task-1', 'private-run-1', 8)]])); $a->captureControl('private-task-2'); $a->captureControl('private-task-1'); $a->captureControl(); $summary = $a->finish($finishState(1, false)); $expect($summary['persisted'] && $summary['lifecycle_consistent'] && !$summary['independent_cleanup_confirmed'], 'durable two-generation pending evidence is not independent cleanup'); $expect($summary['independently_terminal_generation_count'] === 1 && $summary['pending_generation_count'] === 1 && array_column($summary['generations'], 'generation') === [1, 2], 'direct identity closures never substitute last task or control ordinal'); $expect($summary['generations'][0]['lifecycle']['persisted_run_status'] === 'stopped' && $summary['generations'][1]['lifecycle']['persisted_run_status'] === 'running', 'archive and active original pair map to their own wire generation'); $expect($a->finish($finishState(0, true)) === $summary, 'finished audit and pending footer immutable'); $private($summary); foreach (['unknown', 'task_only', 'foreign_control', 'false_footer', 'oversize_control', 'malformed_control'] as $kind) { [$a, $path, $auditPath] = $make(); $identity = $a->observe($wire()); if ($kind !== 'unknown') $identity('private-task', $kind === 'task_only' ? '' : 'private-run'); $a->transferClosed(1, ['transport_closed_ms' => 3, 'transport_exit' => 'natural_eof'], 20.0); $r = $record('private-task', 'private-run', 1, 'running'); if ($kind === 'foreign_control') $r['upstream']['workflow_run_id'] = 'foreign-private-run'; file_put_contents($path, $kind === 'oversize_control' ? str_repeat('x', 1048577) : ($kind === 'malformed_control' ? '{' : $json($r))); $a->captureControl(); $summary = $a->finish($finishState($kind === 'unknown' ? 0 : 1, $kind === 'false_footer')); $expect(!$summary['independent_cleanup_confirmed'] && $summary['pending_generation_count'] === 1, 'unknown/foreign/malformed evidence cannot certify terminal ' . $kind); if (in_array($kind, ['oversize_control', 'malformed_control'], true)) $expect(!$summary['persisted'], 'bounded control parser fails audit statically ' . $kind); else $expect($summary['persisted'], 'unconfirmed valid private evidence remains durable ' . $kind); $private($summary); } // An optional audit observer must not wait indefinitely on a peer's control // lock. The child holds only this freshly created synthetic file, then exits. [$a, $path, $auditPath] = $make(); $code = '$h=fopen($argv[1],"rb");flock($h,LOCK_EX);echo "locked\\n";fflush(STDOUT);usleep(350000);flock($h,LOCK_UN);fclose($h);'; $pipes = []; $process = proc_open([PHP_BINARY, '-r', $code, $path], [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes, null, null, ['bypass_shell' => true]); if (!is_resource($process)) throw new RuntimeException('Synthetic lock child unavailable'); fclose($pipes[0]); $ready = fgets($pipes[1]); $before = hrtime(true); $a->captureControl(); $elapsed = (hrtime(true) - $before) / 1e6; $stderr = stream_get_contents($pipes[2]); fclose($pipes[1]); fclose($pipes[2]); $childExit = proc_close($process); $expect($ready === "locked\n" && $stderr === '' && $childExit === 0, 'synthetic lock child completed and joined'); $expect($elapsed < 100.0, 'optional control audit read does not block on an exclusively held peer file lock'); $a->finish($finishState(0, false)); $observations[] = ['label' => 'exclusive_control_lock', 'capture_elapsed_ms' => $elapsed, 'child_exit' => $childExit]; $expect(!class_exists('think\\App', false) && !class_exists('app\\adminapi\\service\\AssistantRequestControl', false), 'pure helper review never imports moving production or framework'); echo $json(['scope' => 'independent immutable r26 audit helper review', 'assertions' => $checks, 'failures' => $failures, 'observations' => $observations, 'real_network_calls' => 0, 'real_model_calls' => 0]), "\n"; } finally { $real = realpath($base); $temp = realpath(sys_get_temp_dir()); if ($real === false || $temp === false || !str_starts_with(str_replace('\\', '/', $real), rtrim(str_replace('\\', '/', $temp), '/') . '/r26-independent-audit-')) throw new RuntimeException('Synthetic cleanup boundary'); $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($real, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST); foreach ($iterator as $entry) { if ($entry->isLink()) throw new RuntimeException('Synthetic cleanup symlink'); $entry->isDir() ? rmdir($entry->getPathname()) : unlink($entry->getPathname()); } rmdir($real); } exit($failures === [] ? 0 : 1);