30, 'max_memory_usage_mb' => 256, 'min_cache_hit_rate' => 0.7, 'max_memory_pressure' => 0.8, 'min_items_per_second' => 10, ]; private const array QUALITY_WEIGHTS = [ 'performance' => 0.3, 'memory_efficiency' => 0.25, 'cache_effectiveness' => 0.2, 'reliability' => 0.15, 'maintainability' => 0.1, ]; public function __construct( private readonly Clock $clock, private readonly ?Logger $logger = null ) { } /** * Perform comprehensive quality validation */ public function validateQuality( UnifiedDiscoveryService $service, DiscoveryContext $context, ?DiscoveryRegistry $registry = null ): DiscoveryQualityReport { $startTime = microtime(true); $startMemory = memory_get_usage(true); $this->logger?->info('Starting discovery quality validation', [ 'context_key' => $context->getCacheKey(), ]); // Performance validation $performanceScore = $this->validatePerformance($service, $context, $registry); // Memory efficiency validation $memoryScore = $this->validateMemoryEfficiency($service, $startMemory); // Cache effectiveness validation $cacheScore = $this->validateCacheEffectiveness($service); // Reliability validation $reliabilityScore = $this->validateReliability($service); // Maintainability validation $maintainabilityScore = $this->validateMaintainability($service, $registry); // Calculate overall quality score $overallScore = $this->calculateOverallScore([ 'performance' => $performanceScore, 'memory_efficiency' => $memoryScore, 'cache_effectiveness' => $cacheScore, 'reliability' => $reliabilityScore, 'maintainability' => $maintainabilityScore, ]); $validationTime = microtime(true) - $startTime; $report = new DiscoveryQualityReport( overallScore: $overallScore, performanceScore: $performanceScore, memoryScore: $memoryScore, cacheScore: $cacheScore, reliabilityScore: $reliabilityScore, maintainabilityScore: $maintainabilityScore, validationTime: $validationTime, recommendations: $this->generateRecommendations($overallScore, [ 'performance' => $performanceScore, 'memory_efficiency' => $memoryScore, 'cache_effectiveness' => $cacheScore, 'reliability' => $reliabilityScore, 'maintainability' => $maintainabilityScore, ]), timestamp: $this->clock->now() ); $this->logger?->info('Discovery quality validation completed', [ 'overall_score' => $overallScore->toString(), 'validation_time' => $validationTime, 'quality_rating' => $report->getQualityRating(), ]); return $report; } /** * Validate performance characteristics */ private function validatePerformance( UnifiedDiscoveryService $service, DiscoveryContext $context, ?DiscoveryRegistry $registry ): Score { $score = 100; $issues = []; try { // Test discovery timing if registry not provided if ($registry === null) { $startTime = microtime(true); $registry = $service->discoverWithOptions($context->options); $discoveryTime = microtime(true) - $startTime; } else { $discoveryTime = 5.0; // Assume reasonable time if registry provided } // Check discovery time if ($discoveryTime > self::PERFORMANCE_THRESHOLDS['max_discovery_time_seconds']) { $penalty = min(30, ($discoveryTime - self::PERFORMANCE_THRESHOLDS['max_discovery_time_seconds']) * 2); $score -= $penalty; $issues[] = "Discovery took {$discoveryTime}s (threshold: " . self::PERFORMANCE_THRESHOLDS['max_discovery_time_seconds'] . "s)"; } // Check throughput $itemsCount = count($registry); $itemsPerSecond = $itemsCount / max($discoveryTime, 0.1); if ($itemsPerSecond < self::PERFORMANCE_THRESHOLDS['min_items_per_second']) { $score -= 15; $issues[] = "Low throughput: {$itemsPerSecond} items/s (threshold: " . self::PERFORMANCE_THRESHOLDS['min_items_per_second'] . ")"; } // Check for performance bottlenecks $healthStatus = $service->getHealthStatus(); if (isset($healthStatus['memory_management']['memory_pressure'])) { $memoryPressure = (float) $healthStatus['memory_management']['memory_pressure']; if ($memoryPressure > self::PERFORMANCE_THRESHOLDS['max_memory_pressure']) { $score -= 20; $issues[] = "High memory pressure: {$memoryPressure} (threshold: " . self::PERFORMANCE_THRESHOLDS['max_memory_pressure'] . ")"; } } } catch (\Throwable $e) { $score -= 50; $issues[] = "Performance test failed: " . $e->getMessage(); } if (! empty($issues)) { $this->logger?->warning('Performance validation issues detected', [ 'issues' => $issues, 'score' => $score, ]); } return Score::fromRatio(max(0, $score), 100); } /** * Validate memory efficiency */ private function validateMemoryEfficiency(UnifiedDiscoveryService $service, int $startMemory): Score { $score = 100; $issues = []; try { $currentMemory = memory_get_usage(true); $memoryUsed = $currentMemory - $startMemory; $memoryUsedMB = $memoryUsed / 1024 / 1024; // Check memory usage if ($memoryUsedMB > self::PERFORMANCE_THRESHOLDS['max_memory_usage_mb']) { $penalty = min(40, ($memoryUsedMB - self::PERFORMANCE_THRESHOLDS['max_memory_usage_mb']) / 10); $score -= $penalty; $issues[] = "High memory usage: {$memoryUsedMB}MB (threshold: " . self::PERFORMANCE_THRESHOLDS['max_memory_usage_mb'] . "MB)"; } // Check memory management statistics $memoryStats = $service->getMemoryStatistics(); if (isset($memoryStats['memory_status']['memory_pressure'])) { $pressure = $memoryStats['memory_status']['memory_pressure']; if ($pressure > 0.9) { $score -= 25; $issues[] = "Critical memory pressure: {$pressure}"; } elseif ($pressure > 0.8) { $score -= 15; $issues[] = "High memory pressure: {$pressure}"; } } // Check for memory leaks if (isset($memoryStats['guard_statistics']['emergency_mode']) && $memoryStats['guard_statistics']['emergency_mode']) { $score -= 30; $issues[] = "Memory guard in emergency mode"; } } catch (\Throwable $e) { $score -= 25; $issues[] = "Memory efficiency test failed: " . $e->getMessage(); } if (! empty($issues)) { $this->logger?->warning('Memory efficiency validation issues detected', [ 'issues' => $issues, 'score' => $score, ]); } return Score::fromRatio(max(0, $score), 100); } /** * Validate cache effectiveness */ private function validateCacheEffectiveness(UnifiedDiscoveryService $service): Score { $score = 100; $issues = []; try { $healthStatus = $service->getHealthStatus(); // Check if cache is enabled if (! isset($healthStatus['cache']['memory_aware']) || ! $healthStatus['cache']['memory_aware']) { $score -= 20; $issues[] = "Memory-aware caching not enabled"; } // For now, assume good cache performance if no issues detected // In a real implementation, you would track cache hit rates over time } catch (\Throwable $e) { $score -= 30; $issues[] = "Cache effectiveness test failed: " . $e->getMessage(); } if (! empty($issues)) { $this->logger?->warning('Cache effectiveness validation issues detected', [ 'issues' => $issues, 'score' => $score, ]); } return Score::fromRatio(max(0, $score), 100); } /** * Validate system reliability */ private function validateReliability(UnifiedDiscoveryService $service): Score { $score = 100; $issues = []; try { // Test basic functionality $testResults = $service->test(); if ($testResults['overall_status'] !== 'healthy') { $score -= 40; $issues[] = "Service health check failed: " . $testResults['overall_status']; } // Check component statuses foreach ($testResults['components'] as $component => $status) { if (is_array($status) && isset($status['status']) && $status['status'] === 'error') { $score -= 15; $issues[] = "Component {$component} has error: " . ($status['error'] ?? 'unknown'); } } } catch (\Throwable $e) { $score -= 50; $issues[] = "Reliability test failed: " . $e->getMessage(); } if (! empty($issues)) { $this->logger?->warning('Reliability validation issues detected', [ 'issues' => $issues, 'score' => $score, ]); } return Score::fromRatio(max(0, $score), 100); } /** * Validate maintainability aspects */ private function validateMaintainability(UnifiedDiscoveryService $service, ?DiscoveryRegistry $registry): Score { $score = 100; $issues = []; try { // Check if registry has reasonable structure if ($registry !== null && count($registry) === 0) { $score -= 10; $issues[] = "Empty discovery registry - may indicate configuration issues"; } // Check health status structure $healthStatus = $service->getHealthStatus(); $expectedKeys = ['service', 'cache', 'memory_management', 'components']; foreach ($expectedKeys as $key) { if (! isset($healthStatus[$key])) { $score -= 5; $issues[] = "Missing health status key: {$key}"; } } } catch (\Throwable $e) { $score -= 20; $issues[] = "Maintainability test failed: " . $e->getMessage(); } if (! empty($issues)) { $this->logger?->debug('Maintainability validation issues detected', [ 'issues' => $issues, 'score' => $score, ]); } return Score::fromRatio(max(0, $score), 100); } /** * Calculate overall quality score */ private function calculateOverallScore(array $scores): Score { $weightedSum = 0; $totalWeight = 0; foreach (self::QUALITY_WEIGHTS as $category => $weight) { if (isset($scores[$category])) { $weightedSum += $scores[$category]->toDecimal() * $weight; $totalWeight += $weight; } } $overallScore = $totalWeight > 0 ? $weightedSum / $totalWeight : 0; return Score::fromRatio((int) ($overallScore * 100), 100); } /** * Generate quality improvement recommendations */ private function generateRecommendations(Score $overallScore, array $categoryScores): array { $recommendations = []; // Overall recommendations if ($overallScore->toDecimal() < 0.6) { $recommendations[] = 'CRITICAL: Overall quality score is below acceptable threshold - immediate action required'; } elseif ($overallScore->toDecimal() < 0.8) { $recommendations[] = 'Quality score indicates room for improvement - consider optimization'; } // Category-specific recommendations foreach ($categoryScores as $category => $score) { if ($score->toDecimal() < 0.7) { $recommendations[] = match ($category) { 'performance' => 'Performance optimization needed - consider enabling parallel processing and reducing batch sizes', 'memory_efficiency' => 'Memory usage is high - enable memory monitoring and optimize memory management strategies', 'cache_effectiveness' => 'Cache performance is poor - review cache configuration and implement cache warming', 'reliability' => 'System reliability issues detected - investigate component health and error handling', 'maintainability' => 'Maintainability concerns found - review configuration and system structure', default => "Improve {$category} score through system optimization" }; } } if (empty($recommendations)) { $recommendations[] = 'Quality metrics are within acceptable ranges - continue monitoring'; } return $recommendations; } /** * Validate specific quality criteria */ public function validateCriteria(UnifiedDiscoveryService $service, array $criteria): array { $results = []; foreach ($criteria as $criterion => $expectedValue) { try { $result = match ($criterion) { 'max_discovery_time' => $this->checkDiscoveryTime($service, $expectedValue), 'max_memory_usage' => $this->checkMemoryUsage($service, $expectedValue), 'min_cache_hit_rate' => $this->checkCacheHitRate($service, $expectedValue), 'service_health' => $this->checkServiceHealth($service, $expectedValue), default => ['valid' => false, 'error' => "Unknown criterion: {$criterion}"] }; $results[$criterion] = $result; } catch (\Throwable $e) { $results[$criterion] = [ 'valid' => false, 'error' => "Validation failed: " . $e->getMessage(), ]; } } return $results; } /** * Check discovery time criterion */ private function checkDiscoveryTime(UnifiedDiscoveryService $service, float $maxSeconds): array { // This would require actual timing - simplified for example return [ 'valid' => true, 'message' => 'Discovery time validation not implemented in test environment', ]; } /** * Check memory usage criterion */ private function checkMemoryUsage(UnifiedDiscoveryService $service, int $maxMB): array { $currentMemoryMB = memory_get_usage(true) / 1024 / 1024; return [ 'valid' => $currentMemoryMB <= $maxMB, 'actual_value' => $currentMemoryMB, 'expected_max' => $maxMB, 'message' => $currentMemoryMB <= $maxMB ? 'Memory usage within limits' : 'Memory usage exceeds limits', ]; } /** * Check cache hit rate criterion */ private function checkCacheHitRate(UnifiedDiscoveryService $service, float $minRate): array { // This would require cache statistics - simplified for example return [ 'valid' => true, 'message' => 'Cache hit rate validation not implemented in test environment', ]; } /** * Check service health criterion */ private function checkServiceHealth(UnifiedDiscoveryService $service, string $expectedStatus): array { try { $testResults = $service->test(); $actualStatus = $testResults['overall_status']; return [ 'valid' => $actualStatus === $expectedStatus, 'actual_value' => $actualStatus, 'expected_value' => $expectedStatus, 'message' => $actualStatus === $expectedStatus ? 'Service health as expected' : 'Service health differs from expected', ]; } catch (\Throwable $e) { return [ 'valid' => false, 'error' => 'Health check failed: ' . $e->getMessage(), ]; } } }