withData([ 'operation' => $operation, 'current_memory_mb' => round($currentMemory / 1024 / 1024, 2), 'memory_limit_mb' => round($memoryLimit / 1024 / 1024, 2), 'memory_usage_percent' => round(($currentMemory / $memoryLimit) * 100, 1), ]) ->withDebug([ 'current_memory_bytes' => $currentMemory, 'memory_limit_bytes' => $memoryLimit, ]); return self::fromContext( "Discovery operation '{$operation}' failed due to memory exhaustion", $context, ErrorCode::MEMORY_LIMIT_EXCEEDED )->withRetryAfter(300); // Suggest retry after 5 minutes } /** * Directory scanning failed */ public static function scanFailed(string $directory, string $reason, ?\Throwable $previous = null): self { $context = ExceptionContext::forOperation('discovery.scan_failed', 'FileScanner') ->withData([ 'directory' => $directory, 'reason' => $reason, 'is_readable' => is_readable($directory), 'exists' => file_exists($directory), ]); return self::fromContext( "Failed to scan directory '{$directory}': {$reason}", $context, ErrorCode::FILESYSTEM_READ_ERROR, $previous ); } /** * Cache operation failed */ public static function cacheFailed(string $operation, string $key, ?\Throwable $previous = null): self { $context = ExceptionContext::forOperation('discovery.cache_failed', 'DiscoveryCacheManager') ->withData([ 'cache_operation' => $operation, 'cache_key' => $key, ]) ->withDebug([ 'key_hash' => md5($key), 'operation_timestamp' => time(), ]); return self::fromContext( "Discovery cache operation '{$operation}' failed for key '{$key}'", $context, ErrorCode::CACHE_OPERATION_FAILED, $previous ); } /** * File processing failed */ public static function fileProcessingFailed(string $file, string $reason, ?\Throwable $previous = null): self { $context = ExceptionContext::forOperation('discovery.file_processing_failed', 'FileProcessor') ->withData([ 'file_path' => $file, 'file_size' => file_exists($file) ? filesize($file) : null, 'file_extension' => pathinfo($file, PATHINFO_EXTENSION), 'reason' => $reason, ]); return self::fromContext( "Failed to process file '{$file}': {$reason}", $context, ErrorCode::FILE_PROCESSING_FAILED, $previous ); } /** * Attribute reflection failed */ public static function attributeReflectionFailed(string $className, string $attributeType, ?\Throwable $previous = null): self { $context = ExceptionContext::forOperation('discovery.attribute_reflection_failed', 'AttributeProcessor') ->withData([ 'class_name' => $className, 'attribute_type' => $attributeType, 'class_exists' => class_exists($className), ]); return self::fromContext( "Failed to reflect attribute '{$attributeType}' on class '{$className}'", $context, ErrorCode::REFLECTION_FAILED, $previous ); } /** * Memory guard emergency stop */ public static function emergencyStop(string $reason, array $memoryStats): self { $context = ExceptionContext::forOperation('discovery.emergency_stop', 'MemoryGuard') ->withData([ 'reason' => $reason, 'memory_usage_mb' => round($memoryStats['current_usage'] / 1024 / 1024, 2), 'memory_limit_mb' => round($memoryStats['memory_limit'] / 1024 / 1024, 2), 'memory_pressure' => $memoryStats['memory_pressure'] ?? 'unknown', ]) ->withDebug($memoryStats); return self::fromContext( "Discovery process stopped by memory guard: {$reason}", $context, ErrorCode::EMERGENCY_STOP_TRIGGERED ); } /** * Configuration validation failed */ public static function configurationInvalid(string $field, string $reason): self { $context = ExceptionContext::forOperation('discovery.configuration_invalid', 'DiscoveryConfiguration') ->withData([ 'invalid_field' => $field, 'validation_error' => $reason, ]); return self::fromContext( "Discovery configuration invalid - {$field}: {$reason}", $context, ErrorCode::VAL_CONFIGURATION_INVALID ); } /** * Discovery timeout */ public static function timeout(int $timeoutSeconds, int $actualSeconds): self { $context = ExceptionContext::forOperation('discovery.timeout', 'DiscoveryService') ->withData([ 'timeout_seconds' => $timeoutSeconds, 'actual_seconds' => $actualSeconds, 'exceeded_by_seconds' => $actualSeconds - $timeoutSeconds, ]); return self::fromContext( "Discovery operation timed out after {$actualSeconds}s (limit: {$timeoutSeconds}s)", $context, ErrorCode::OPERATION_TIMEOUT )->withRetryAfter(60); // Suggest retry after 1 minute } /** * Concurrent discovery conflict */ public static function concurrentDiscovery(string $lockId): self { $context = ExceptionContext::forOperation('discovery.concurrent_conflict', 'DiscoveryService') ->withData([ 'lock_id' => $lockId, 'conflict_type' => 'concurrent_discovery', ]); return self::fromContext( "Discovery already in progress (lock: {$lockId})", $context, ErrorCode::RESOURCE_CONFLICT )->withRetryAfter(30); // Suggest retry after 30 seconds } /** * Corrupted discovery data */ public static function corruptedData(string $source, string $reason): self { $context = ExceptionContext::forOperation('discovery.corrupted_data', 'DiscoveryService') ->withData([ 'data_source' => $source, 'corruption_reason' => $reason, ]); return self::fromContext( "Discovery data corrupted in {$source}: {$reason}", $context, ErrorCode::DATA_CORRUPTION_DETECTED ); } /** * Insufficient permissions */ public static function insufficientPermissions(string $path, string $requiredPermission): self { $context = ExceptionContext::forOperation('discovery.insufficient_permissions', 'FileScanner') ->withData([ 'path' => $path, 'required_permission' => $requiredPermission, 'current_permissions' => file_exists($path) ? substr(sprintf('%o', fileperms($path)), -4) : null, ]); return self::fromContext( "Insufficient permissions to access '{$path}' (required: {$requiredPermission})", $context, ErrorCode::PERMISSION_DENIED ); } /** * Resource limit exceeded */ public static function resourceLimitExceeded(string $resource, int $current, int $limit): self { $context = ExceptionContext::forOperation('discovery.resource_limit_exceeded', 'DiscoveryService') ->withData([ 'resource_type' => $resource, 'current_usage' => $current, 'resource_limit' => $limit, 'usage_percentage' => round(($current / $limit) * 100, 1), ]); return self::fromContext( "Resource limit exceeded for {$resource}: {$current}/{$limit}", $context, ErrorCode::RESOURCE_LIMIT_EXCEEDED )->withRetryAfter(60); } /** * Dependency missing */ public static function dependencyMissing(string $dependency, string $requiredFor): self { $context = ExceptionContext::forOperation('discovery.dependency_missing', 'DiscoveryService') ->withData([ 'missing_dependency' => $dependency, 'required_for' => $requiredFor, ]); return self::fromContext( "Missing dependency '{$dependency}' required for {$requiredFor}", $context, ErrorCode::DEPENDENCY_MISSING ); } }