\n", FILE_APPEND); $vm['support_files'][$file] = hash_file('sha256', $variant.'/'.$file); file_put_contents($variant.'/manifest.json', json_encode($vm, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR)); $vh = hash_file('sha256', $variant.'/manifest.json'); $vp = $deploy->plan($variant, $vh); $vu = $deploy->apply($variant, $vh, $vp['target_sha256'], 'Isolated code-only update', true); $check(hash_file('sha256', $clone.'/packages/internal-requisitions/manifest.json') === $vh, 'code-only successor installed over existing provenance'); $deploy->rollback($vu['deployment_id'], 'Isolated successor recovery', true); $check(hash_file('sha256', $clone.'/packages/internal-requisitions/manifest.json') === hash_file('sha256', $bundle.'/manifest.json'), 'code-only successor rollback restores exact candidate'); foreach ($fingerprints as $table => $expected) { $rows = $db->select('select to_jsonb(t)::text as data from "'.$table.'" t order by to_jsonb(t)::text'); if (hash('sha256', json_encode(array_column($rows, 'data'), JSON_THROW_ON_ERROR)) !== $expected) throw new RuntimeException('Update changed '.$table); } $check(true, 'code update and rollback preserve every reproduced data table');