context) ? $run->context : []; $storedTranslation = $this->storedOperationRunTranslation($context); if ($storedTranslation !== null) { $storedEnvelope = ReasonResolutionEnvelope::fromArray($storedTranslation); if ($storedEnvelope instanceof ReasonResolutionEnvelope) { $nextSteps = $this->operationRunNextSteps($context); if ($storedEnvelope->nextSteps === [] && $nextSteps !== []) { return $storedEnvelope->withNextSteps($nextSteps); } return $storedEnvelope; } } $contextReasonCode = data_get($context, 'execution_legitimacy.reason_code') ?? data_get($context, 'reason_code') ?? data_get($context, 'baseline_compare.reason_code'); if (is_string($contextReasonCode) && trim($contextReasonCode) !== '') { return $this->translateOperationRunReason(trim($contextReasonCode), $surface, $context); } $failureReasonCode = data_get($run->failure_summary, '0.reason_code'); if (! is_string($failureReasonCode) || trim($failureReasonCode) === '') { return null; } $failureReasonCode = trim($failureReasonCode); if (! $this->isDirectlyTranslatableOperationReason($failureReasonCode)) { return null; } $envelope = $this->translateOperationRunReason($failureReasonCode, $surface, $context); if (! $envelope instanceof ReasonResolutionEnvelope) { return null; } if ($envelope->nextSteps !== []) { return $envelope; } $legacyNextSteps = $this->operationRunNextSteps($context); return $legacyNextSteps !== [] ? $envelope->withNextSteps($legacyNextSteps) : $envelope; } /** * @param array $context * @return array|null */ private function storedOperationRunTranslation(array $context): ?array { $storedTranslation = $context['reason_translation'] ?? data_get($context, 'baseline_compare.reason_translation'); return is_array($storedTranslation) ? $storedTranslation : null; } /** * @param array $context * @return array */ private function operationRunNextSteps(array $context): array { $nextSteps = $context['next_steps'] ?? data_get($context, 'baseline_compare.next_steps'); return is_array($nextSteps) ? NextStepOption::collect($nextSteps) : []; } /** * @param array $context */ private function translateOperationRunReason( string $reasonCode, string $surface, array $context, ): ?ReasonResolutionEnvelope { return $this->reasonTranslator->translate($reasonCode, surface: $surface, context: $context); } private function isDirectlyTranslatableOperationReason(string $reasonCode): bool { if ($reasonCode === ProviderReasonCodes::UnknownError) { return false; } return ProviderReasonCodes::isKnown($reasonCode) || ExecutionDenialReasonCode::tryFrom($reasonCode) instanceof ExecutionDenialReasonCode || LifecycleReconciliationReason::tryFrom($reasonCode) instanceof LifecycleReconciliationReason || TenantOperabilityReasonCode::tryFrom($reasonCode) instanceof TenantOperabilityReasonCode || RbacReason::tryFrom($reasonCode) instanceof RbacReason; } public function forProviderReason( Tenant $tenant, string $reasonCode, ?ProviderConnection $connection = null, string $surface = 'detail', ): ?ReasonResolutionEnvelope { return $this->reasonTranslator->translate( reasonCode: $reasonCode, artifactKey: ProviderReasonTranslator::ARTIFACT_KEY, surface: $surface, context: [ 'tenant' => $tenant, 'connection' => $connection, ], ); } public function forTenantOperabilityReason( TenantOperabilityReasonCode|string|null $reasonCode, string $surface = 'detail', ): ?ReasonResolutionEnvelope { $normalizedCode = $reasonCode instanceof TenantOperabilityReasonCode ? $reasonCode->value : $reasonCode; return $this->reasonTranslator->translate( reasonCode: $normalizedCode, artifactKey: ReasonTranslator::TENANT_OPERABILITY_ARTIFACT, surface: $surface, ); } public function forRbacReason(RbacReason|string|null $reasonCode, string $surface = 'detail'): ?ReasonResolutionEnvelope { $normalizedCode = $reasonCode instanceof RbacReason ? $reasonCode->value : $reasonCode; return $this->reasonTranslator->translate( reasonCode: $normalizedCode, artifactKey: ReasonTranslator::RBAC_ARTIFACT, surface: $surface, ); } /** * @param array $context */ public function forArtifactTruth( ?string $reasonCode, string $surface = 'detail', array $context = [], ): ?ReasonResolutionEnvelope { return $this->reasonTranslator->translate( reasonCode: $reasonCode, artifactKey: self::GOVERNANCE_ARTIFACT_TRUTH_ARTIFACT, surface: $surface, context: $context, ); } public function diagnosticCode(?ReasonResolutionEnvelope $envelope): ?string { return $envelope?->diagnosticCode(); } public function primaryLabel(?ReasonResolutionEnvelope $envelope): ?string { return $envelope?->operatorLabel; } public function shortExplanation(?ReasonResolutionEnvelope $envelope): ?string { return $envelope?->shortExplanation; } public function dominantCauseLabel(?ReasonResolutionEnvelope $envelope): ?string { return $envelope?->operatorLabel; } public function dominantCauseExplanation(?ReasonResolutionEnvelope $envelope): ?string { return $envelope?->shortExplanation; } public function trustImpact(?ReasonResolutionEnvelope $envelope): ?string { return $envelope?->trustImpact; } public function ownerLayer(?ReasonResolutionEnvelope $envelope): ?string { return $envelope?->ownerLayer(); } public function ownerNamespace(?ReasonResolutionEnvelope $envelope): ?string { return $envelope?->ownerNamespace(); } public function platformReasonFamily(?ReasonResolutionEnvelope $envelope): ?string { return $envelope?->platformReasonFamily(); } public function platformReasonFamilyLabel(?ReasonResolutionEnvelope $envelope): ?string { return $envelope?->platformReasonFamilyEnum()?->label(); } public function ownerLabel(?ReasonResolutionEnvelope $envelope): ?string { $ownerNamespace = $envelope?->ownerNamespace(); if (! is_string($ownerNamespace) || trim($ownerNamespace) === '') { return null; } return match (true) { str_starts_with($ownerNamespace, 'provider.') => 'Provider-owned detail', str_starts_with($ownerNamespace, 'governance.') => 'Governance detail', $ownerNamespace === 'rbac.intune' => 'Intune RBAC detail', $ownerNamespace === 'tenant_operability', $ownerNamespace === 'execution_denial', $ownerNamespace === 'operation_lifecycle', $ownerNamespace === 'reason_translation.fallback' => 'Platform core', default => match ($envelope?->ownerLayer()) { 'provider_owned' => 'Provider-owned detail', 'domain_owned' => 'Domain-owned detail', 'platform_core' => 'Platform core', 'compatibility_alias' => 'Compatibility alias', 'compatibility_only' => 'Compatibility-only detail', default => Str::of((string) $envelope?->ownerLayer())->replace('_', ' ')->headline()->toString(), }, }; } /** * @return array{ * owner_label: string, * owner_layer: string, * owner_namespace: string, * boundary_classification: ?string, * boundary_label: ?string, * family: string, * family_label: string, * diagnostic_code: string * }|null */ public function semantics(?ReasonResolutionEnvelope $envelope): ?array { if (! $envelope instanceof ReasonResolutionEnvelope) { return null; } $boundary = $this->reasonTranslator->boundaryClassificationForEnvelope($envelope); $family = $envelope->platformReasonFamilyEnum(); $ownerLabel = $this->ownerLabel($envelope); if (! is_string($ownerLabel) || $family === null) { return null; } return [ 'owner_label' => $ownerLabel, 'owner_layer' => (string) $envelope->ownerLayer(), 'owner_namespace' => (string) $envelope->ownerNamespace(), 'boundary_classification' => $boundary, 'boundary_label' => is_string($boundary) ? Str::of($boundary)->replace('_', ' ')->headline()->toString() : null, 'family' => $family->value, 'family_label' => $family->label(), 'diagnostic_code' => $envelope->diagnosticCode(), ]; } public function absencePattern(?ReasonResolutionEnvelope $envelope): ?string { return $envelope?->absencePattern; } public function guidance(?ReasonResolutionEnvelope $envelope): ?string { return $envelope?->guidanceText(); } /** * @return array */ public function bodyLines(?ReasonResolutionEnvelope $envelope, bool $includeGuidance = true): array { return $envelope?->toBodyLines($includeGuidance) ?? []; } }