> $items * @param array $sourceMetadata * @return array{allowed: bool, failure_code?: string, reason_code?: string, blocked_index?: int, identity_state?: string, duplicate_identity?: bool} */ public function evaluateCollection( ManagedEnvironment $tenant, ProviderConnection $providerConnection, TenantConfigurationResourceType $resourceType, array $items, array $sourceMetadata, ): array { $seenKeys = []; foreach ($items as $index => $item) { $identity = $this->identityEvaluator->evaluate( result: $this->identityResolver->resolve($resourceType, $item, $sourceMetadata), tenant: $tenant, providerConnection: $providerConnection, resourceType: $resourceType, ); if ($identity->identityState !== IdentityState::Stable) { return [ 'allowed' => false, 'failure_code' => self::FAILURE_CODE, 'reason_code' => $this->reasonCodeForIdentityState($identity->identityState), 'blocked_index' => $index, 'identity_state' => $identity->identityState->value, ]; } if (isset($seenKeys[$identity->canonicalResourceKey])) { return [ 'allowed' => false, 'failure_code' => self::FAILURE_CODE, 'reason_code' => 'duplicate_stable_identity', 'blocked_index' => $index, 'identity_state' => IdentityState::IdentityConflict->value, 'duplicate_identity' => true, ]; } $seenKeys[$identity->canonicalResourceKey] = true; } return ['allowed' => true]; } private function reasonCodeForIdentityState(IdentityState $identityState): string { return match ($identityState) { IdentityState::IdentityConflict => 'identity_conflict', IdentityState::MissingExternalId => 'missing_stable_external_id', IdentityState::UnsupportedIdentity => 'unsupported_identity', IdentityState::Derived => 'derived_identity_blocked', IdentityState::Stable => 'stable_identity', }; } }