Preserve request-stream ownership during server cleanup

KL
2mo ago
+270-195

Extract server stream ownership and cancellation cleanup from #3511. Each HTTP request closes its own streams, so an older connection cannot remove a successor's streams after request-ID reuse; legacy SSE also closes all owned memory streams.

Replay locking and buffering are left to the next PR. The router regressions run on both asyncio and trio without enabling Trio across the suite or requiring an HTTPX2 update.

Validation

macOS, Python 3.14, locked dependencies: ./scripts/test passes with 5,981 passed, 9 skipped, 1 xfailed, 100% line/branch coverage, and strict-no-cover passing. Ruff lint/format and Pyright pass.

Stack

Part 1 of 5, based on main. Merge the focused fixes before the final backend-enablement change in #3511.

AI Disclaimer

This PR was developed with the assistance of either Claude or Codex. I've reviewed and verified the changes.