'testing', 'DB_CONNECTION' => 'pgsql', 'DB_HOST' => '127.0.0.1', 'DB_PORT' => '55441', 'DB_DATABASE' => 'simulator_fiscal_delta_20261021_test', 'DB_USERNAME' => 'postgres', 'DB_PASSWORD' => '', 'DB_URL' => '', 'SESSION_DRIVER' => 'array'] as $k => $v) { putenv($k.'='.$v); $_ENV[$k] = $_SERVER[$k] = $v; } require __DIR__.'/../vendor/autoload.php'; $app = require __DIR__.'/../bootstrap/app.php'; $app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap(); use Illuminate\Support\Facades\DB; use App\Models\Opportunity; use App\Services\CorridorAgribusinessOpportunities; use App\Services\OpportunityPromotion; $target = DB::selectOne('SELECT current_database() AS name, inet_server_port() AS port'); if (! app()->environment('testing') || $target->name !== 'simulator_fiscal_delta_20261021_test' || (int) $target->port !== 55441) throw new RuntimeException('QA only'); config(['portal.profile_access_enabled' => true]); $actor = App\Models\User::findOrFail(295); // QA-role simulation, like the bounded tests; this is not evidence of a real production MFA login. session(['portal.mfa_actor' => $actor->id, 'portal.mfa_at' => time(), 'login.id' => null]); $request = Illuminate\Http\Request::create('/minhas-oportunidades', 'GET'); $request->setUserResolver(fn () => $actor); $app->instance('request', $request); $entries = app(CorridorAgribusinessOpportunities::class)->entries(); $dir = storage_path('app/private/agribusiness-opportunities-20261023'); $records = Opportunity::whereIn('management_creation_key', array_column($entries, 'key'))->get(); if (! file_exists($dir.'/before-disclosure.json')) file_put_contents($dir.'/before-disclosure.json', json_encode($records->map(fn ($r) => $r->getRawOriginal())->all(), JSON_THROW_ON_ERROR)); $result = DB::transaction(function () use ($actor, $entries) { DB::select('SELECT pg_advisory_xact_lock(231026, 34)'); $result = []; foreach ($entries as $entry) { $record = Opportunity::where('management_creation_key', $entry['key'])->lockForUpdate()->firstOrFail(); if ($record->status !== 'published') { $values = app(App\Services\OpportunityManagement::class)->values($record); if ($record->status !== 'draft' || ($values['canonical']['official_title'] ?? null) !== $entry['title'] || ($values['canonical']['executive_summary'] ?? null) !== $entry['summary']) throw new RuntimeException('Edited or withdrawn record requires individual review: '.$record->id); $input = $record->workflow_context['promotional_summary']['input']; $preview = app(OpportunityPromotion::class)->preview($actor, $record, [...$input, 'source_date' => null, 'action' => 'disclose', 'etag' => app(App\Services\OpportunityManagement::class)->etag($record)]); app(OpportunityPromotion::class)->confirm($actor, $record->id, ['token' => $preview['token'], 'operation_key' => (string) Illuminate\Support\Str::uuid(), 'confirm' => true, 'reason' => 'QA automatizada: divulgação das 34 fichas de Agronegócio expressamente instruída pela Tempo; em preparação, sem autorização de execução.']); } elseif (data_get($record->workflow_context, 'publication.purpose') !== OpportunityPromotion::PURPOSE) throw new RuntimeException('Different publication preserved'); $result[] = ['id' => $record->id, 'title' => $entry['title'], 'corridor' => $entry['corridor'], 'url' => '/oportunidades/'.$record->slug]; } return $result; }); $receipt = ['target' => $target, 'published' => count($result), 'authentication' => 'QA role simulation only; no production authentication claimed', 'source_sha256' => CorridorAgribusinessOpportunities::SOURCE_HASH, 'records' => $result, 'active_writes' => 0]; file_put_contents($dir.'/disclosure-receipt.json', json_encode($receipt, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); echo json_encode(['published' => count($result), 'target' => $target, 'active_writes' => 0]).PHP_EOL;