ExecutionDenialClass::ScopeDenied, self::MissingCapability => ExecutionDenialClass::CapabilityDenied, self::TenantNotOperable => ExecutionDenialClass::TenantNotOperable, self::ProviderConnectionInvalid, self::WriteGateBlocked, self::ExecutionPrerequisiteInvalid => ExecutionDenialClass::PrerequisiteInvalid, self::InitiatorMissing, self::InitiatorNotEntitled => ExecutionDenialClass::InitiatorInvalid, }; } public function message(): string { return match ($this) { self::WorkspaceMismatch => 'Operation blocked because the queued run no longer matches the current workspace scope.', self::TenantNotEntitled => 'Operation blocked because the target tenant is no longer entitled for this run.', self::MissingCapability => 'Operation blocked because the initiating actor no longer has the required capability.', self::TenantNotOperable => 'Operation blocked because the target tenant is not currently operable for this action.', self::TenantMissing => 'Operation blocked because the target tenant could not be resolved at execution time.', self::InitiatorMissing => 'Operation blocked because the initiating actor could not be resolved at execution time.', self::InitiatorNotEntitled => 'Operation blocked because the initiating actor is no longer entitled to the tenant.', self::ProviderConnectionInvalid => 'Operation blocked because the provider connection is no longer valid for the queued scope.', self::WriteGateBlocked => 'Operation blocked because write hardening currently refuses execution for this tenant.', self::ExecutionPrerequisiteInvalid => 'Operation blocked because the queued execution prerequisites are no longer satisfied.', }; } public function operatorLabel(): string { return match ($this) { self::WorkspaceMismatch => 'Workspace context changed', self::TenantNotEntitled => 'Tenant access removed', self::MissingCapability => 'Permission required', self::TenantNotOperable => 'Tenant not ready', self::TenantMissing => 'Tenant record unavailable', self::InitiatorMissing => 'Initiator no longer available', self::InitiatorNotEntitled => 'Initiator lost tenant access', self::ProviderConnectionInvalid => 'Provider connection needs review', self::WriteGateBlocked => 'Write protection blocked execution', self::ExecutionPrerequisiteInvalid => 'Execution prerequisite changed', }; } public function shortExplanation(): string { return match ($this) { self::WorkspaceMismatch => 'The queued run no longer matches the current workspace scope.', self::TenantNotEntitled => 'The queued tenant is no longer entitled for this run.', self::MissingCapability => 'The initiating actor no longer has the capability required for this queued run.', self::TenantNotOperable => 'The target tenant is not currently operable for this action.', self::TenantMissing => 'The target tenant could not be resolved when execution resumed.', self::InitiatorMissing => 'The initiating actor could not be resolved when execution resumed.', self::InitiatorNotEntitled => 'The initiating actor is no longer entitled to the target tenant.', self::ProviderConnectionInvalid => 'The queued provider connection is no longer valid for this scope.', self::WriteGateBlocked => 'Current write hardening refuses execution for this tenant until the gate is satisfied.', self::ExecutionPrerequisiteInvalid => 'The queued execution prerequisites are no longer satisfied.', }; } public function actionability(): string { return match ($this) { self::TenantNotOperable => 'retryable_transient', self::ProviderConnectionInvalid, self::WriteGateBlocked, self::ExecutionPrerequisiteInvalid => 'prerequisite_missing', default => 'permanent_configuration', }; } /** * @return array */ public function nextSteps(): array { return match ($this) { self::MissingCapability, self::TenantNotEntitled, self::InitiatorNotEntitled, self::WorkspaceMismatch => [ NextStepOption::instruction('Review workspace or tenant access before retrying.', scope: 'workspace'), ], self::TenantNotOperable, self::ExecutionPrerequisiteInvalid => [ NextStepOption::instruction('Review tenant readiness before retrying.', scope: 'tenant'), ], self::ProviderConnectionInvalid => [ NextStepOption::instruction('Review the provider connection before retrying.', scope: 'tenant'), ], self::WriteGateBlocked => [ NextStepOption::instruction('Review the write gate state before retrying.', scope: 'tenant'), ], self::TenantMissing, self::InitiatorMissing => [ NextStepOption::instruction('Requeue the operation from a current tenant context.', scope: 'tenant'), ], }; } /** * @param array $context */ public function toReasonResolutionEnvelope(string $surface = 'detail', array $context = []): ReasonResolutionEnvelope { return new ReasonResolutionEnvelope( internalCode: $this->value, operatorLabel: $this->operatorLabel(), shortExplanation: $this->shortExplanation(), actionability: $this->actionability(), nextSteps: $this->nextSteps(), showNoActionNeeded: false, diagnosticCodeLabel: $this->value, ); } }