Why an internal slot and not a symbol?
Minor question, but it seems like if the [[Metadata]] internal slot were instead a Symbol.metadata ordinary property, then this proposal could be implemented 100% in an ordinary JS library as a decorator. Is that right? What's the reasoning for going down the path of making it more built-in in this way?
In particular, rather than making these new MOP operations, the semantics can be simply, "get the Symbol.metadata, and then get/set the metadata property there; or, create a new empty object and put it in Symbol.metadata if needed".
Primarily, it is to allow metadata mutation on a frozen object. This helps avoid issues with decorator execution order if one decorator freezes the class before another can apply metadata. It also enforces a structure on the data that is consistent that you cannot guarantee if it is a symbol-named property.
I am considering adding a compatibility mode to read metadata from Symbol.metadata if it is present, but that is fairly low on my list of priorities at the moment. I will revisit this when I have more time available.