[ty] Track unused-binding captures across nested scopes (#25536)
## Summary
We previously determined whether an enclosing binding was used by
reusing the snapshots created for type inference. This misses captures
that originate in a descendant scope across a lazy function boundary:
```python
def outer(i: int):
def inner():
return [[k for k in range(i)] for _ in range(2)]
return inner
```
The read of `i` belongs to a comprehension scope nested under `inner`.
Snapshot traversal stops at the lazy `inner` scope, so the final
unused-binding pass could not connect that descendant read to `outer`'s
parameter and incorrectly reported `i` as unused.
This tracks capture usage independently from type-resolution snapshots.
When a scope completes, unresolved free-name uses are propagated to its
parent until the completed scope that owns the name can claim them.
We defer that resolution until each candidate enclosing scope is
complete because a later binding can change which scope owns the name:
```python
def outer():
x = 0
def middle():
def inner():
return x
x = 1
return inner
return middle
```
Here, Python treats `x` as local to `middle` even though its binding
follows `inner`, so `inner` captures `x = 1` and `outer`'s `x = 0`
remains unused. Pending captures retain the bindings visible when the
nested scope was created and, for lazy scopes, later bindings and
reassignments that can reach the capture.
Regression coverage includes nested comprehensions, captured parameters,
shadowed outer bindings, bindings introduced after nested functions,
intermediate reassignments, and `nonlocal` proxy scopes.
Closes https://github.com/astral-sh/ty/issues/3442.
---------
Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>