$proof['restored_target'], 'qa_current' => $qa] as $label => $target) { if ((int) $target['port'] !== 55441 || ! preg_match('/^(country_candidate|desk_restore)_\d{8}_\d{6}_test$/D', $target['database'])) { throw new RuntimeException('Isolated inventory target refused'); } $pdo = new PDO('pgsql:host=127.0.0.1;port=55441;dbname='.$target['database'], 'postgres', '', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]); $pdo->exec('BEGIN READ ONLY'); $identity = $pdo->query("SELECT current_database() AS database,inet_server_port() AS port,current_setting('transaction_read_only') AS read_only")->fetch(PDO::FETCH_ASSOC); if ($identity['database'] !== $target['database'] || (int) $identity['port'] !== 55441 || $identity['read_only'] !== 'on') { throw new RuntimeException('Read-only isolation refused'); } $inventories[$label] = ['identity' => $identity, 'tables' => $pdo->query("SELECT schemaname||'.'||tablename FROM pg_tables WHERE schemaname NOT IN ('pg_catalog','information_schema') ORDER BY 1")->fetchAll(PDO::FETCH_COLUMN), 'migrations' => $pdo->query('SELECT migration FROM migrations ORDER BY migration')->fetchAll(PDO::FETCH_COLUMN)]; $pdo->exec('ROLLBACK'); } $extra = array_values(array_diff($inventories['qa_current']['tables'], $inventories['active_restored']['tables'])); $absent = array_values(array_diff($inventories['active_restored']['tables'], $inventories['qa_current']['tables'])); $result = ['at' => gmdate('c'), 'backup_code_hash' => $proof['code_hash'], 'inventories' => $inventories, 'additional_qa_tables' => $extra, 'missing_in_qa_tables' => $absent, 'additional_qa_migrations' => array_values(array_diff($inventories['qa_current']['migrations'], $inventories['active_restored']['migrations'])), 'active_writes' => 0]; file_put_contents($dir.'/country-schema-compare-20261011.json', json_encode($result, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR)); echo json_encode(['restored_tables' => count($inventories['active_restored']['tables']), 'qa_tables' => count($inventories['qa_current']['tables']), 'extra' => $extra, 'missing' => $absent, 'active_writes' => 0]).PHP_EOL;