Thanks for writing this up!
It's somewhat unfortunate to not issue a runtime warning, especially since I imagine most users would ideally want one. The SC has also indicated they'd like static typing to feel more cohesive with the runtime, so we should try harder to find something that works for both.
As we discussed and you mention here, an opt-in kwarg (a la Protocol's runtime_checkable) seems like a promising solution. In fact, thinking about it more, I think it's feasible for runtime warning to be opt-out. Walking through the cases in a little bit more detail:
> When the decorator is applied to a class or an overload, the warning would not be raised as expected.
I think there are reasonable possible semantics for decorating a class.
This seems to me a reasonable default; users can opt-out if they need something different.
Overloads are trickier. However, I think it's reasonable that type checkers could provide an error if a deprecated overload isn't opted out of the runtime warning (if we have an opt-in flag, type checkers would probably also want such a check). If we feel like that's not sufficient, it seems feasible to detect this situation at runtime and error out.
> Users may want to control the warn call in more detail (e.g., changing the warning class).
Having the option allows users full control. I think opt-out is the right default here.
> typing.py generally aims to avoid affecting runtime behavior.
This is true, but what we often really want to avoid is runtime type checking, and this isn't really runtime type checking.
I really do believe that most users will want some runtime warning here.
Absent specific reasons to avoid affecting runtime behaviour, I'm not sure how much stock I put in this as a general guideline, given SC feedback about wanting a more cohesive language.