There is no such thing as One True Vocabulary Type..
..because there are multiple vocabularies.
Polymorphic allocators, and types using them, have two aspects:
  Types like std::vector have both of these aspects intact.
  Types like the envisioned allocator-aware std::function
  and std::optional do not. The latter is a mistake.
  Instead of adding library types that work with just std::polymorphic_allocator,  (and thus hard-code the propagation and scoping), we should
  split such facilities into a generic part that has an allocator as a template
  parameter, and a more-specific part (an alias, perhaps) that packages
  a common allocator (perhaps a polymorphic_allocator) with
  the generic part.
When standardizing utility types, we should consider standardizing nice packages for common scenarios, but we should not forget to standardize extensible and customizable building blocks.
  A std::polymorphic_allocator is fine for the vocabulary
  it intends to serve. However, that vocabulary, where POCMA is false,
  is not suitable for all use cases under the sun. That vocabulary has
  two problems:
  
move_if_noexcept will
      copy, because the allocators are not always equal and they don't
      propagate.polymorphic_allocator
      wrapping a default memory resource.
  This is problematic. I can write a Major Architectural Sub-System (MASS)
  where I have a MASS-specific memory arena shared by all objects living
  under the control of that MASS. All propagation within the MASS is always
  fine. Yet polymorphic_allocator will defeat this idea since
  its POCMA and SOCCC will result in a default arena being used at the
  slightest provocation.
It seems that the argument is that if I would transfer an object out of a function when the allocator of the object is using a local arena, the allocator should not try to propagate because the arena will have expired. Another argument seems to be that between two different MASSes, the arenas would be different and therefore allocators should not propagate.
That's all fine and good. That's what propagation traits are for. If I have a local object using a local arena, I will give it an allocator that does not propagate. If I expose allocator-aware objects between two different MASSes, I will give those MASSes different allocator types, so objects will not just propagate from
    std::vector<Foo, Mass1Allocator> get_stuff();
  
  to a
  
    std::vector<Foo, Mass2Allocator> my_local = Mass1::get_stuff();
  
  In other words: both the static and dynamic aspects of an allocator/mechanism
  combination serve a purpose. Please don't drop either of those aspects
  when designing allocator-aware non-container types, like function
  or optional.
  In the pseudo-example above, Mass1Allocator and Mass2Allocator
  are BOTH polymorphic. They are, however, not
  std::polymorphic_allocator, but rather reusing it
  as an implementation detail. The allocators propagate, because
  they propagate inside MASS 1 and inside MASS 2, but not across the
  MASS boundary.
  I can still do all the good things that memory_resources allow me to
  do without "infecting" a type. I can have multiple different memory
  resources as the mechanism of a std::vector<Foo, Mass1Allocator>.
  What Mass1Allocator allows me to do is define propagation that is different
  from std::polymorphic_allocator, and what Mass1Allocator
  and Mass2Allocator allow me to do is to have two different
  polymorphic-allocator-aware types that are not implicitly interoperable.
In other words, the best of both worlds.
  Well, if function and optional support only
  std::polymorphic_allocator, I lose the aforementioned
  abilities. I need to write my own allocator-aware function and optional
  to re-gain the static aspects of allocators. That would seem unfortunate.
Instead of
    template <class T>> class __alloc_optional {...};
    template <class T> using optional = metaprogram_select<T, __alloc_optional<T>, optional<T>>;
    
  
Do this instead:
    template <class T, class Alloc> class basic_optional {...};
    template <class T> using optional = metaprogram_select<T, basic_optional<T, std::polymorphic_allocator<T>>, optional<T>>;
    
  
In other words, instead of
std::polymorphic_allocatorstd::polymorphic_allocatoror an allocator-unaware type
  Polymorphic allocators are nice and simple, agreed. Even the package
  of std::polymorphic_allocator is nice and simple,
  for the vocabulary that works with it. For vocabularies that don't,
  we reach for other kinds of allocators. And we want those allocators
  to be customization points, and thus our allocator-aware types should
  use those customization points. We can still package a
  pmr::optional so that it out-of-the-box gives us
  an optional with a standard polymorphic allocator, but we shouldn't
  close the door of customizing the behavior of an allocator-aware optional.
  Yes, this is more complex to specify. It's barely more complex to implement.
  It's not more complex to design. One of the main headaches of designing
  an allocator-aware optional was figuring out how it should propagate
  in various scenarios. A basic_optional is _simpler_ in that
  regard, to specify, and to design; its allocator propagates the way the
  propagation traits of the allocator tell it to propagate. Layering
  a std::polymorphic_allocator on top of such a design
  is easy, it just plops in without any ado. And the design retains
  the ability to change how the allocator behaves, by using the
  basic_optional 'directly', or rather as a building block.