Duck typing in pyspecs (upgrade_to_* functions)
There are cases in pyspecs (found during static analysis of them), which rely on duck typing.
For example, upgrade_to_altair(phase0.BeaconState) in Altair or upgrade_to_phase1(phase0.BeaconState) in Phase1.
The functions receive an instance of phase0.BeaconState and then pass it or its components to other functions, which expect instances of altair or phase1 classes (e.g. BeaconState, Version, Slot, etc), e.g. get_current_epoch(altair.BeaconState).
This works with the dynamic type checking of Python, but leads to static type checking problems, for which there are no straightforward way to fix. It actually may hide bugs (e.g. #1924), which can be revealed with static type checking, e.g. when a new field introduced in altair or phase1, which is absent in phase0.
I'm not aware of real existing bugs introduced by mixing altair/phase classes with phase0 ones, but there are examples which are close to. For example, the generated altair/spec.py file contains functions like get_matching_source_attestations or process_participation_record_updates, which either directly or indirectly accesses current_epoch_attestations field of BeaconState, which is present in the phase0.BeaconState, but absent in the altair.BeaconState.