create(); $dispatched = 0; $result = app(ProviderOperationStartGate::class)->start( tenant: $tenant, connection: null, operationType: 'provider.connection.check', dispatcher: function () use (&$dispatched): void { $dispatched++; }, ); expect($dispatched)->toBe(0) ->and($result->status)->toBe('blocked') ->and($result->run->status)->toBe(OperationRunStatus::Completed->value) ->and($result->run->outcome)->toBe(OperationRunOutcome::Blocked->value) ->and($result->run->context['reason_code'] ?? null)->toBe(ProviderReasonCodes::ProviderConnectionMissing) ->and($result->run->context['next_steps'] ?? [])->not->toBeEmpty(); }); it('Spec081 blocks provider operation starts when default connection has no credential', function (): void { $tenant = Tenant::factory()->create(); $connection = ProviderConnection::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'provider' => 'microsoft', 'is_default' => true, 'status' => 'connected', ]); $result = app(ProviderOperationStartGate::class)->start( tenant: $tenant, connection: null, operationType: 'provider.connection.check', dispatcher: static function (): void {}, ); expect($result->status)->toBe('blocked') ->and($result->run->context['provider_connection_id'] ?? null)->toBe((int) $connection->getKey()) ->and($result->run->context['reason_code'] ?? null)->toBe(ProviderReasonCodes::ProviderCredentialMissing) ->and($result->run->outcome)->toBe(OperationRunOutcome::Blocked->value); }); it('Spec081 returns deterministic invalid reason when data corruption creates multiple defaults', function (): void { $tenant = Tenant::factory()->create(); DB::statement('DROP INDEX IF EXISTS provider_connections_default_unique'); $first = ProviderConnection::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'provider' => 'microsoft', 'is_default' => true, 'status' => 'connected', ]); ProviderCredential::factory()->create([ 'provider_connection_id' => (int) $first->getKey(), ]); $second = ProviderConnection::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'provider' => 'microsoft', 'is_default' => true, 'status' => 'connected', ]); ProviderCredential::factory()->create([ 'provider_connection_id' => (int) $second->getKey(), ]); $result = app(ProviderOperationStartGate::class)->start( tenant: $tenant, connection: null, operationType: 'provider.connection.check', dispatcher: static function (): void {}, ); expect($result->status)->toBe('blocked') ->and($result->run->context['reason_code'] ?? null)->toBe(ProviderReasonCodes::ProviderConnectionInvalid) ->and($result->run->context['reason_code_extension'] ?? null)->toBe('ext.multiple_defaults_detected') ->and($result->run->outcome)->toBe(OperationRunOutcome::Blocked->value); });