> It's fine to encode rules directly into the type system, but only for rules that are known to be fixed (or at least not likely to ever change) throughout the lifetime of the project.
But then you lose the benefits a type system offers during refactoring. When business logic does change, if it's linked to the type system, then the logic is forced to change consistently throughout your system.
Of course, you don't want to be forced to change all your code whenever any business logic changes. But you never are. Basic separation of concerns should ensure that different pieces of logic are coupled to different types, such that the blast radius of any type change is limited.
Consider the example from the article, where the PaymentStatus type winds up with a whole bunch of variants. Code that deals with the status of a payment really needs to know all the different statuses a payment could have. If you add a PendingApproval variant to PaymentStatus, your refund workflow should break, because it needs to know to cancel the approval process without issuing a payment when the order is still pending approval. Meanwhile, code that doesn't deal with payments directly can treat that type as a black box.