The project-scoped recovery pass asked for the global window's exhaustion
signal but never for its own. A scoped query carries a raw candidate window
of its own (limit * 8, re-widened to limit * 32), and compression segments
plus the post-projection visibility filters are spent from that window
BEFORE the logical slice. A lineage-heavy project therefore came back short
with its window fully consumed while older assigned conversations of the same
project still waited behind it, and the loop advanced to the next project —
leaving that project under-delivered on every rebuild.
The scoped query now asks for `return_window_exhaustion`, and a binding
window buys exactly one re-query at the widest limit this pass is allowed to
scan (`query_limit`). The retry is bounded to one extra query per starved
project and cannot out-read the pass's own scan budget.
The regression test builds a starved project whose scoped raw window is
filled by its own compression segments, with an older conversation of the
same project just behind the window. Against the previous head that
conversation was lost — the project recovered only its chain tip — while the
new head recovers it and pays exactly two scoped queries (limits 4 then 8:
one widening step, inside the ceiling). Verified red without the fix and
green with it; the full file is 73 passed, and the sibling suites this branch
touches (test_issue2628_cli_sessions_perf, test_issue4842_cron_projection_perf)
bring the run to 86 passed.