registerCurrentModel(); * * // Analyze with tracking * $result = $adapter->analyzeWithTracking($features, $groundTruth); * ``` */ final readonly class QueueAnomalyModelAdapter { private const MODEL_NAME = 'queue-anomaly'; private const CURRENT_VERSION = '1.0.0'; public function __construct( private ModelRegistry $registry, private ModelPerformanceMonitor $performanceMonitor, private JobAnomalyDetector $detector ) {} /** * Register current queue anomaly model in registry */ public function registerCurrentModel(?array $performanceMetrics = null): ModelMetadata { $version = Version::fromString(self::CURRENT_VERSION); // Check if already registered if ($this->registry->exists(self::MODEL_NAME, $version)) { return $this->registry->get(self::MODEL_NAME, $version); } // Create metadata $metadata = ModelMetadata::forQueueAnomaly( version: $version, configuration: $this->detector->getConfiguration() ); // Add performance metrics if provided if ($performanceMetrics !== null) { $metadata = $metadata->withPerformanceMetrics($performanceMetrics); } // Register in registry $this->registry->register($metadata); return $metadata; } /** * Analyze job features with automatic performance tracking * * @param JobFeatures $features Job execution features * @param bool|null $groundTruth Ground truth (if known) - true if job is anomalous * * @return array Analysis result with tracking info */ public function analyzeWithTracking( JobFeatures $features, ?bool $groundTruth = null ): array { // Perform ML analysis $analysisResult = $this->detector->detect($features); // Determine prediction $prediction = $analysisResult->isAnomalous; $confidence = $analysisResult->anomalyScore->getValue() / 100.0; // Convert 0-100 to 0.0-1.0 // Track prediction in performance monitor $this->performanceMonitor->trackPrediction( modelName: self::MODEL_NAME, version: Version::fromString(self::CURRENT_VERSION), prediction: $prediction, actual: $groundTruth, confidence: $confidence, features: $this->extractFeatureSummary($analysisResult) ); // Convert result to array format $resultArray = [ 'is_anomalous' => $analysisResult->isAnomalous, 'anomaly_score' => $analysisResult->anomalyScore->getValue(), 'feature_scores' => array_map( fn($score) => $score->getValue(), $analysisResult->featureScores ), 'detected_patterns' => $analysisResult->detectedPatterns, 'primary_indicator' => $analysisResult->primaryIndicator, 'success' => true ]; // Add tracking info $resultArray['tracking'] = [ 'model_name' => self::MODEL_NAME, 'model_version' => self::CURRENT_VERSION, 'prediction' => $prediction ? 'anomalous' : 'normal', 'ground_truth' => $groundTruth, 'tracked' => true, ]; return $resultArray; } /** * Get current model performance metrics */ public function getCurrentPerformanceMetrics(): array { return $this->performanceMonitor->getCurrentMetrics( self::MODEL_NAME, Version::fromString(self::CURRENT_VERSION) ); } /** * Check if model performance has degraded */ public function checkPerformanceDegradation(float $thresholdPercent = 0.05): array { return $this->performanceMonitor->getPerformanceDegradationInfo( self::MODEL_NAME, Version::fromString(self::CURRENT_VERSION), $thresholdPercent ); } /** * Update model configuration in registry */ public function updateConfiguration(array $newConfiguration): void { $version = Version::fromString(self::CURRENT_VERSION); $metadata = $this->registry->get(self::MODEL_NAME, $version); if ($metadata === null) { throw new \RuntimeException( 'Model not registered. Call registerCurrentModel() first.' ); } $updated = $metadata->withConfiguration($newConfiguration); $this->registry->update($updated); } /** * Deploy current model to production */ public function deployToProduction(): void { $version = Version::fromString(self::CURRENT_VERSION); $metadata = $this->registry->get(self::MODEL_NAME, $version); if ($metadata === null) { throw new \RuntimeException( 'Model not registered. Call registerCurrentModel() first.' ); } $deployed = $metadata->withDeployment( environment: 'production', deployedAt: Timestamp::now() ); $this->registry->update($deployed); } /** * Get model metadata */ public function getModelMetadata(): ?ModelMetadata { return $this->registry->get( self::MODEL_NAME, Version::fromString(self::CURRENT_VERSION) ); } /** * Extract feature summary for tracking */ private function extractFeatureSummary(JobAnomalyResult $result): array { return [ 'feature_count' => count($result->featureScores), 'pattern_count' => count($result->detectedPatterns), 'primary_indicator' => $result->primaryIndicator, 'is_anomalous' => $result->isAnomalous, ]; } }