40 lines
3.4 KiB
PHP
40 lines
3.4 KiB
PHP
<?php
|
|
// Read-only reconnaissance of the existing isolated full QA; never boot the active app.
|
|
use App\Models\Opportunity;
|
|
use App\Services\OpportunityCanonicalContract;
|
|
use App\Services\OpportunityManagement;
|
|
use App\Services\OpportunityResources;
|
|
use App\Services\PortalProfileAccess;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
$root = dirname(__DIR__);
|
|
$dir = $root.'/storage/app/private/investmoz-v2/portal-audit';
|
|
$plan = json_decode(file_get_contents($dir.'/portal-stability-latest.json'), true, 512, JSON_THROW_ON_ERROR);
|
|
putenv('STABILITY_QA_MODE=consumers');
|
|
$app = require $plan['source'].'/tools/portal-stability-runtime.php';
|
|
$identity = DB::selectOne('SELECT current_database() AS database, inet_server_port() AS port');
|
|
throw_unless($identity->database === $plan['consumer_environment']['target']['database'] && (int) $identity->port === 55441 && str_ends_with($identity->database, '_test'), RuntimeException::class, 'Isolated QA required.');
|
|
$proof = DB::transaction(function () use ($identity): array {
|
|
DB::statement('SET TRANSACTION READ ONLY');
|
|
$cases = [];
|
|
foreach ([30,31,32,33,34,35,52] as $id) {
|
|
$record = Opportunity::findOrFail($id);
|
|
$canonical = app(OpportunityManagement::class)->values($record)['canonical'] ?? [];
|
|
$errors = [];
|
|
try { app(OpportunityCanonicalContract::class)->validateSubmission($record); }
|
|
catch (Illuminate\Validation\ValidationException $e) { $errors = $e->errors(); }
|
|
$cases[$id] = ['category'=>$record->opportunity_category, 'state'=>app(PortalProfileAccess::class)->state($record),
|
|
'public_status'=>$record->status, 'version'=>$record->management_version, 'owner'=>$record->owner_user_id,
|
|
'gates'=>app(OpportunityCanonicalContract::class)->gates($record), 'reviews'=>array_keys($record->workflow_context['reviews'] ?? []),
|
|
'semantic_errors'=>$errors, 'resource_counts'=>array_map(fn($kind)=>count($canonical[$kind] ?? []),array_combine(OpportunityResources::KINDS,OpportunityResources::KINDS))];
|
|
}
|
|
return ['at'=>gmdate('c'), 'target'=>$identity, 'active_writes'=>0, 'result'=>'read_only_QA', 'cases'=>$cases,
|
|
'installed'=>DB::table('migrations')->whereIn('migration',['2026_10_09_020000_extend_opportunity_management','2026_10_09_030000_extend_opportunity_resources','2026_10_10_040000_create_portal_profile_authorization'])->pluck('migration')->all(),
|
|
'profile_available'=>app(PortalProfileAccess::class)->available(), 'resources_installed'=>app(OpportunityResources::class)->installed(),
|
|
'ClamD_real'=>app(App\Services\Malware\MalwareScanner::class)->health(),
|
|
'GD_WebP'=>function_exists('imagewebp'), 'php'=>PHP_VERSION,
|
|
'service_sources'=>array_map(fn($name)=>(new ReflectionClass($name))->getFileName(),[OpportunityManagement::class,App\Services\OpportunityReviewMateriality::class])];
|
|
});
|
|
file_put_contents($dir.'/functional-status-qa-20261011.json',json_encode($proof,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR));
|
|
echo json_encode(['result'=>$proof['result'],'target'=>$identity,'installed'=>$proof['installed'],'profile_available'=>$proof['profile_available'],'resources_installed'=>$proof['resources_installed'],'cases'=>$proof['cases'],'ClamD_real'=>$proof['ClamD_real'],'GD_WebP'=>$proof['GD_WebP'],'service_sources'=>$proof['service_sources'],'active_writes'=>0],JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR).PHP_EOL;
|