make(Kernel::class)->bootstrap(); verifyEducation(! $app->configurationIsCached() && IsolatedQaDatabase::allowsSchemaChanges() && DB::connection()->getDatabaseName() === getenv('DB_DATABASE'), 'Effective education QA target rejected.'); DB::statement("SET statement_timeout = '45s'"); $drafts = app(EducationDeclarationDrafts::class); verifyEducation($drafts->installed(), 'Migrate the disposable database first.'); $directory = storage_path('app/private/education-draft-concurrency-20261102'); if (($argv[1] ?? null) === '--worker') { $path = realpath($argv[2] ?? ''); verifyEducation($path !== false && dirname($path) === realpath($directory), 'Worker context path rejected.'); $context = json_decode(file_get_contents($path), true, 512, JSON_THROW_ON_ERROR); verifyEducation($context['database'] === DB::connection()->getDatabaseName() && in_array($context['kind'], ['demands', 'capacities'], true), 'Worker database/kind differs.'); $task = $argv[3] ?? ''; $index = (int) ($argv[4] ?? -1); verifyEducation(in_array($index, [0, 1], true) && in_array($task, ['create', 'save', 'submit'], true), 'Worker task rejected.'); $actor = User::findOrFail($context['actor']); verifyEducation($actor->email === 'synthetic-education-concurrency@example.invalid', 'Synthetic identity required.'); config(['education.enabled' => true, 'portal.managers' => [$actor->email]]); DB::select("SELECT set_config('application_name', ?, false)", ['edu-qa-'.$context['run'].'-'.$task.'-'.$index]); $input = ['version_no' => $context['version_no'], 'payload' => $context['payload'], 'client_key' => $context['client_key']]; if ($task === 'save') { $input['payload']['qualification'] = 'SYNTHETIC concurrent edit '.$context['phase'].' '.$index; } try { $result = $task === 'submit' ? $drafts->submit($actor, $context['kind'], $context['id'], $input) : $drafts->save($actor, $context['kind'], $task === 'create' ? null : $context['id'], $input); echo json_encode(['status' => 'ok', 'id' => $result['id'], 'version_no' => $result['version_no'], 'state' => $result['state'], 'record_id' => $result['record_id'], 'payload_sha256' => hash('sha256', json_encode($result['payload'], JSON_THROW_ON_ERROR))], JSON_THROW_ON_ERROR).PHP_EOL; } catch (HttpExceptionInterface $error) { echo json_encode(['status' => $error->getStatusCode() === 409 ? 'conflict' : 'http_error', 'code' => $error->getStatusCode()], JSON_THROW_ON_ERROR).PHP_EOL; } exit(0); } verifyEducation(($argv[1] ?? null) === '--run', 'Explicit --run required.'); $lock = fopen(storage_path('framework/qa-database-'.hash('sha256', '127.0.0.1:55441:'.DB::connection()->getDatabaseName()).'.lock'), 'c'); verifyEducation($lock !== false && flock($lock, LOCK_EX | LOCK_NB), 'Another runner owns this QA database.'); foreach (['users', 'education_declaration_drafts', 'labour_demands', 'training_capacities'] as $table) { verifyEducation(DB::table($table)->count() === 0, 'Disposable database must be empty; existing records will not be reset.'); } if (! is_dir($directory)) { mkdir($directory, 0700, true); } $actor = User::factory()->create(['name' => 'SYNTHETIC QA education concurrency', 'email' => 'synthetic-education-concurrency@example.invalid']); config(['education.enabled' => true, 'portal.managers' => [$actor->email]]); $province = (string) Str::uuid(); DB::table('geo_locations')->insert(['id' => $province, 'name' => 'SYNTHETIC QA province', 'code' => $province, 'location_type' => 'province']); $project = Project::create(['code' => (string) Str::uuid(), 'name' => 'SYNTHETIC QA project', 'status' => 'draft']); $provider = TrainingProvider::create(['name' => 'SYNTHETIC QA provider', 'status' => 'candidate']); $course = Course::create(['provider_id' => $provider->id, 'code' => (string) Str::uuid(), 'title' => 'SYNTHETIC QA course', 'status' => 'draft']); $base = ['occupation_id' => Occupation::create(['code' => (string) Str::uuid(), 'name' => 'SYNTHETIC QA occupation'])->id, 'skill_id' => Skill::create(['code' => (string) Str::uuid(), 'name' => 'SYNTHETIC QA skill'])->id, 'geo_location_id' => $province, 'qualification' => 'SYNTHETIC QA original qualification', 'quantity' => 15, 'period_start' => today()->addMonth()->toDateString(), 'period_end' => today()->addMonths(2)->toDateString(), 'reference_date' => today()->toDateString(), 'valid_until' => today()->addYear()->toDateString(), 'source' => 'SYNTHETIC QA only; not actual workforce or training data.']; $context = ['run' => bin2hex(random_bytes(5)), 'database' => DB::connection()->getDatabaseName(), 'actor' => $actor->id]; $checks = []; $phase = function (string $name, array $tasks) use (&$context, &$checks, $directory): array { $path = $directory.'/'.$context['run'].'-'.$name.'.json'; file_put_contents($path, json_encode([...$context, 'phase' => $name], JSON_THROW_ON_ERROR)); DB::beginTransaction(); DB::table('users')->where('id', $context['actor'])->lockForUpdate()->firstOrFail(); $processes = $observed = []; foreach ($tasks as $index => $task) { $process = new Process([PHP_BINARY, __FILE__, '--worker', $path, $task, (string) $index], dirname(__DIR__)); $process->setTimeout(60); $process->start(); $processes[] = $process; $deadline = microtime(true) + 40; do { DB::select('SELECT pg_stat_clear_snapshot()'); $waiting = DB::selectOne("SELECT pid,wait_event,pg_blocking_pids(pid) AS blockers FROM pg_stat_activity WHERE datname=current_database() AND application_name=? AND wait_event_type='Lock'", ['edu-qa-'.$context['run'].'-'.$task.'-'.$index]); if ($waiting) { $observed[] = (array) $waiting; break; } verifyEducation($process->isRunning(), 'Worker exited before observed overlap: '.$name.' '.$process->getErrorOutput()); usleep(100000); } while (microtime(true) < $deadline); verifyEducation($waiting !== null, 'No actual overlapping lock wait: '.$name); } DB::commit(); $results = []; foreach ($processes as $process) { $process->wait(); verifyEducation($process->isSuccessful(), 'Worker failed: '.$name.' '.$process->getErrorOutput()); $results[] = json_decode(trim($process->getOutput()), true, 512, JSON_THROW_ON_ERROR); } $checks[$name] = ['overlap_observed' => $observed, 'results' => $results]; echo json_encode(['phase' => $name, 'workers' => 2, 'lock_overlap_verified' => true], JSON_THROW_ON_ERROR).PHP_EOL; return $results; }; foreach (['demands', 'capacities'] as $kind) { $context = [...$context, 'kind' => $kind, 'version_no' => 0, 'client_key' => (string) Str::uuid(), 'payload' => $kind === 'demands' ? [...$base, 'project_id' => $project->id, 'employer' => 'SYNTHETIC QA employer'] : [...$base, 'course_id' => $course->id]]; $result = $phase($kind.'_duplicate_creation', ['create', 'create']); verifyEducation(array_column($result, 'status') === ['ok', 'ok'] && $result[0]['id'] === $result[1]['id'] && $result[0]['version_no'] === 1 && $result[1]['version_no'] === 1, 'Creation duplicated draft or revision.'); $context = [...$context, 'id' => $result[0]['id'], 'version_no' => 1]; $result = $phase($kind.'_conflicting_edits', ['save', 'save']); $statuses = array_column($result, 'status'); sort($statuses); verifyEducation($statuses === ['conflict', 'ok'], 'Concurrent stale edit not rejected.'); $saved = $drafts->show($actor, $kind, $context['id']); verifyEducation($saved['version_no'] === 2 && $saved['payload']['qualification'] === 'SYNTHETIC concurrent edit '.$kind.'_conflicting_edits 0', 'Winning edit not preserved.'); $context = [...$context, 'version_no' => 2, 'payload' => $saved['payload']]; $result = $phase($kind.'_duplicate_submission', ['submit', 'submit']); verifyEducation(array_column($result, 'status') === ['ok', 'ok'] && $result[0]['record_id'] === $result[1]['record_id'] && $result[0]['state'] === 'submitted' && $result[1]['version_no'] === 3, 'Duplicate submitted record.'); $table = $kind === 'demands' ? 'labour_demands' : 'training_capacities'; verifyEducation(DB::table($table)->count() === 1, 'Duplicate business submission.'); foreach ([['save', 'submit'], ['submit', 'save']] as $order) { $created = $drafts->save($actor, $kind, null, ['version_no' => 0, 'client_key' => (string) Str::uuid(), 'payload' => $context['payload']]); $context = [...$context, 'id' => $created['id'], 'version_no' => 1]; $before = DB::table($table)->count(); $result = $phase($kind.'_'.implode('_before_', $order), $order); verifyEducation(array_column($result, 'status') === ['ok', 'conflict'], 'Save/submission order not respected.'); $current = $drafts->show($actor, $kind, $context['id']); $submitted = $order[0] === 'submit'; verifyEducation($current['state'] === ($submitted ? 'submitted' : 'draft') && $current['version_no'] === 2 && DB::table($table)->count() === $before + ($submitted ? 1 : 0), 'Race lost draft state or duplicated declaration.'); } } verifyEducation(DB::table('education_declaration_drafts')->count() === 6 && DB::table('labour_demands')->count() === 2 && DB::table('training_capacities')->count() === 2, 'Final counts differ.'); verifyEducation(DB::table('education_declaration_drafts')->where('state', 'submitted')->whereNull('reference_snapshot')->count() === 0 && DB::table('audit_events')->where('source_system', 'education-drafts')->where('action', 'draft_submitted')->count() === 4, 'Submission snapshots/audit lost.'); echo json_encode(['result' => 'passed', 'database' => DB::connection()->getDatabaseName(), 'synthetic' => true, 'phases' => $checks, 'counts' => ['drafts' => 6, 'labour_demands' => 2, 'training_capacities' => 2, 'submission_audits' => 4], 'active_writes' => 0, 'external_messages' => 0], JSON_THROW_ON_ERROR).PHP_EOL; } catch (Throwable $error) { if (isset($app) && DB::connection()->transactionLevel() > 0) { DB::rollBack(); } fwrite(STDERR, json_encode(['result' => 'failed', 'exception' => $error::class, 'code' => $error->getCode(), 'message' => $error instanceof RuntimeException ? $error->getMessage() : 'Inspect isolated worker failure.'], JSON_THROW_ON_ERROR).PHP_EOL); exit(1); }