getMessage(), $text), $text); } }; $apply = function (CodeDeployment $deployment, string $bundle, string $hash, ?callable $checkpoint = null) { $plan = $deployment->plan($bundle, $hash); return $deployment->apply($bundle, $hash, $plan['target_sha256'], 'Synthetic version operator', true, $checkpoint); }; $copy = updateFixture($host, $manifest); $d = new CodeDeployment($copy); $v1 = $apply($d, $old, $oldHash); $unowned = updateFixture($host, $manifest); $copyBundle($old, $unowned.'/packages/internal-requisitions'); $deny(fn () => (new CodeDeployment($unowned))->plan($new, $newHash), 'sem proveniência'); $mutant = sys_get_temp_dir().'/sgf-update-schema-'.bin2hex(random_bytes(6)); $copyBundle($new, $mutant); $changed = json_decode(file_get_contents($mutant.'/manifest.json'), true, 32, JSON_THROW_ON_ERROR); $driver = 'integrations/sgf/operational/Installation.php'; file_put_contents($mutant.'/'.$driver, file_get_contents($mutant.'/'.$driver)."\n// Synthetic schema-driver revision\n"); $changed['support_files'][$driver] = hash_file('sha256', $mutant.'/'.$driver); file_put_contents($mutant.'/manifest.json', json_encode($changed, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR)); $deny(fn () => $d->plan($mutant, hash_file('sha256', $mutant.'/manifest.json')), 'Transição de schema'); $plan = $d->plan($new, $newHash); $check($plan['previous']['deployment_id'] === $v1['deployment_id'], 'plan binds update to active installation'); $v2 = $apply($d, $new, $newHash); $check(hash_file('sha256', $copy.'/packages/internal-requisitions/manifest.json') === $newHash, 'new version applied without source connection'); $check(is_dir($copy.'/storage/app/private/module-deployments/'.$v2['deployment_id'].'/previous-bundle'), 'previous version preserved locally'); $deny(fn () => $d->rollback($v1['deployment_id'], 'Synthetic out-of-order', true), 'fora de ordem'); $deny(fn () => $d->apply($old, $oldHash, $plan['target_sha256'], 'Synthetic stale replay', true), 'versão activa'); $file = array_key_first($manifest['host_overlays']); $content = file_get_contents($copy.'/'.$file); file_put_contents($copy.'/'.$file, $content."\n// local work\n"); $deny(fn () => $d->plan($new, $newHash), 'Código aplicado alterado'); file_put_contents($copy.'/'.$file, $content); file_put_contents($copy.'/packages/internal-requisitions/local-extension.php', ' $d->plan($new, $newHash), 'Conteúdo extra'); unlink($copy.'/packages/internal-requisitions/local-extension.php'); $d->rollback($v2['deployment_id'], 'Synthetic version rollback', true); $check(hash_file('sha256', $copy.'/packages/internal-requisitions/manifest.json') === $oldHash, 'rollback restores previous bundle exactly'); $check(json_decode(file_get_contents($copy.'/storage/app/private/module-deployments/current.json'), true)['deployment_id'] === $v1['deployment_id'], 'rollback restores active provenance'); $retryPlan = $d->plan($new, $newHash); $check($retryPlan['deployment_id'] !== $v2['deployment_id'], 'new attempt preserves rolled-back journal'); $deny(fn () => $apply($d, $new, $newHash, function ($step) { if ($step === 'previous-bundle-preserved') { throw new RuntimeException('Injected update switch failure'); } }), 'Injected update switch failure'); $d->rollback($retryPlan['deployment_id'], 'Synthetic interrupted transition', true); $check(hash_file('sha256', $copy.'/packages/internal-requisitions/manifest.json') === $oldHash, 'interrupted transition recovers previous version'); $again = $apply($d, $new, $newHash); $check($again['deployment_id'] !== $retryPlan['deployment_id'], 'reapply creates a separate audited attempt'); $d->rollback($again['deployment_id'], 'Synthetic clean transition rollback', true); $d->rollback($v1['deployment_id'], 'Synthetic first installation rollback', true); $check(! is_dir($copy.'/packages/internal-requisitions'), 'complete rollback restores original host composition'); $native = updateFixture($host, $manifest, true); $nativeDeploy = new CodeDeployment($native); $environment = ['APP_ENV' => 'production', 'APP_DEBUG' => 'false', 'APP_BASE_PATH' => $native, 'APP_KEY' => 'base64:'.base64_encode(random_bytes(32)), 'DB_CONNECTION' => 'sqlite', 'DB_DATABASE' => ':memory:', 'DB_URL' => '', 'CACHE_STORE' => 'array', 'SESSION_DRIVER' => 'file', 'QUEUE_CONNECTION' => 'sync']; $previousEnv = []; foreach ($environment as $key => $value) { $previousEnv[$key] = getenv($key); putenv($key.'='.$value); } $server = null; $start = function () use ($native) { $socket = stream_socket_server('tcp://127.0.0.1:0'); $name = stream_socket_get_name($socket, false); fclose($socket); $port = (int) substr(strrchr($name, ':'), 1); $process = proc_open([PHP_BINARY, '-S', '127.0.0.1:'.$port, '-t', $native.'/public'], [0 => ['pipe', 'r'], 1 => ['file', $native.'/storage/logs/server.log', 'a'], 2 => ['file', $native.'/storage/logs/server.log', 'a']], $pipes, $native); fclose($pipes[0]); for ($i = 0; $i < 100; $i++) { $probe = @fsockopen('127.0.0.1', $port); if ($probe) { fclose($probe); break; }usleep(50000); } return [$process, $port]; }; $stop = function ($process) { proc_terminate($process); proc_close($process); }; $status = function ($port, $path) { $context = stream_context_create(['http' => ['ignore_errors' => true, 'header' => "Accept: application/json\r\n", 'timeout' => 10]]); file_get_contents('http://127.0.0.1:'.$port.$path, false, $context); preg_match('/\s([0-9]{3})\s/', $http_response_header[0], $match); return (int) $match[1]; }; try { $a = $apply($nativeDeploy, $old, $oldHash); $nativeDeploy->rebuildCaches($a['deployment_id'], 'Synthetic native cache V1', true); $check(is_file($native.'/bootstrap/cache/config.php') && is_file($native.'/bootstrap/cache/routes-v7.php') && is_file($native.'/bootstrap/cache/events.php'), 'native Laravel config route and event caches built'); $b = $apply($nativeDeploy, $new, $newHash); $check(! is_file($native.'/bootstrap/cache/config.php') && ! is_file($native.'/bootstrap/cache/routes-v7.php'), 'version update invalidates previous native caches'); $deny(fn () => $nativeDeploy->rebuildCaches($b['deployment_id'], 'Synthetic cache compilation failure', true, function ($command) { if ($command === 'config:cache') { throw new RuntimeException('Injected cache compilation interruption'); } }), 'Injected cache compilation interruption'); $cacheJournal = json_decode(file_get_contents($native.'/storage/app/private/module-deployments/'.$b['deployment_id'].'/journal.json'), true, 32, JSON_THROW_ON_ERROR); $check($cacheJournal['cache_state'] === 'failed' && is_file($native.'/storage/framework/down'), 'partial native cache build is journalled under maintenance'); file_put_contents($native.'/bootstrap/cache/config.php', ' $nativeDeploy->rollback($b['deployment_id'], 'Synthetic conflicting cache rollback', true), 'Cache mudou após compilação'); file_put_contents($native.'/bootstrap/cache/config.php', $compiled); $nativeDeploy->rollback($b['deployment_id'], 'Synthetic cached version rollback', true); $check(! is_file($native.'/bootstrap/cache/config.php') && ! is_file($native.'/bootstrap/cache/routes-v7.php'), 'rollback invalidates registered rebuilt caches'); $nativeDeploy->rebuildCaches($a['deployment_id'], 'Synthetic native cache restored V1', true); $previousCacheHash = hash_file('sha256', $native.'/bootstrap/cache/config.php'); $replayedRollback = $nativeDeploy->rollback($b['deployment_id'], 'Synthetic repeated version rollback', true); $check($replayedRollback['replayed'] && hash_file('sha256', $native.'/bootstrap/cache/config.php') === $previousCacheHash, 'repeated rollback preserves previous-version rebuilt caches'); [$server,$port] = $start(); $check($status($port, '/purchasing/internal-requisitions') === 503, 'previous version restarts with native caches and maintenance'); $stop($server); $server = null; $nativeDeploy->rollback($a['deployment_id'], 'Synthetic native baseline rollback', true); unlink($native.'/storage/framework/down'); [$server,$port] = $start(); $check($status($port, '/purchasing/internal-requisitions') === 404, 'restarted baseline exposes no removed module route'); $check($status($port, '/up') === 200, 'baseline starts after cached deployment rollback'); } finally { if (is_resource($server)) { $stop($server); }foreach ($previousEnv as $key => $value) { putenv($value === false ? $key : $key.'='.$value); } } $check(file_get_contents($host.'/packages/purchasing/current.json') === $pointer, 'destination remains untouched on 0.1.1'); $proof = ['passed' => true, 'checks' => $checks, 'old_candidate' => $old, 'new_candidate' => $new, 'archive' => $prepared['archive'], 'copies' => [$copy, $native, $unowned, $mutant], 'checked_at' => gmdate('c'), 'destination_version' => '0.1.1', 'destination_applied' => false, 'prior_suites_repeated' => false, 'actual_destination_services_touched' => false, 'native_caches_built' => true, 'isolated_server_restarts_verified' => true]; file_put_contents($root.'/docs/proofs/sgf-update-cache-delivery.json', json_encode($proof, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR)); echo json_encode($proof, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR)."\n";