Just thinking on my feet as to how I separate abstractions from indirections and it seems to me that there's a relatively decent rule of thumb to distinguish them: When layer A of code wraps layer B, then there are a few cases:
1) If A is functionally identical to B, then A is a layer of indirection
2) If A is functionally distinct from B, then A is likely an abstraction
3) If A is functionally distinct from B, but B must be considered when
handling A, then A is a leaky abstraction.
The idea is that we try to identify layers of indirection by the fact that they don't provide any functional "value".