Ah, the fact that it didn’t throw an exception on the non-inherited model was due I think to the bug described above - adding another constraint into that model triggered the exception on that one.
So the error I’m dealing with is indeed that the CreateModel operation is incorrectly “seeing” a constraint (that will be handled elsewhere).
So, interestingly, explicitly added constraints are not present in the “fake” model that migrations use, but this class is passed to the contribute_to_class function, so “automatic” constraints added here still get added.
In my case, I was able to avoid adding the constraint if cls.__module__ == '__fake__', but this feels like a dirty solution - I’d be keen to find why cls._meta.constraints is empty when building migrations…