[ty] Fix contravariant type variable bound checking in specialization inference
## Summary
Correctly handle upper bounds for contravariant type variables during specialization
inference. Previously, the type checker incorrectly applied covariant subtyping rules,
requiring the actual type to directly satisfy the bound rather than checking for a
valid intersection.
In contravariant positions, subtyping relationships are inverted. The bug caused
valid code like `f(x: Contra[str])` where `f` expects `Contra[T: int]` to be
incorrectly rejected, when it should solve `T` to `Never` (the intersection of `int`
and `str`).
Closes https://github.com/astral-sh/ty/issues/2427
## Details
- Added `is_contravariant()` helper to `TypeVarVariance` in `variance.rs`
- Updated `SpecializationBuilder::infer_map_impl` in `generics.rs` to treat bounds
and constraints differently based on variance:
* Skip immediate `ty <: bound` check for contravariant upper bounds
* Flip constraint check to `constraint <: ty` for contravariant positions
- Added test case for bounded contravariant type variables in `variance.md`
- All 308 mdtest cases pass & 150 ty_python_semantic unit tests pass