# v3.19.1 — ingest stdio pipe deadlock fix

## The bug

`ingest_codebase` could hang forever — 4.5h+ at 0% CPU on both the Python launcher and the Rust analyzer child. Root cause: batch tool calls each run on a **fresh per-call event loop** in a worker thread, then close it. Call 1 cached the pooled `MCPClient` bound to loop-A; loop-A closed. Call 2 reused the cached client (stale `connected=True`) and created its wait-future on loop-B — but the client's `_read_loop` task lived on dead loop-A, so the child's stdout was never drained. Once the upstream response exceeded the 64KB OS pipe buffer, the Rust child blocked in `write()`, the caller's `await future` never resolved, and both sides slept forever.

This was the upstream cause of the "graph shows only the global domain / stale codebase" reports: a deadlocked or truncated ingest leaves a half-built graph that later runs reuse.

## The fix

- **Loop-liveness guard** — `MCPClient` records its bound event loop at connect; `connected` now returns `False` when that loop is closed or a different loop is running, so the connection pool discards a dead/foreign-loop client and reconnects on the live loop.
- **Bounded call timeout** — new `CORTEX_MCP_CALL_TIMEOUT_S` (default **600s** = 10× the measured 32s analyze latency, down from the old 3600s) makes a wedged call fail loudly in minutes, not hours, with a diagnostic naming the pipe-buffer cause.
- **Regression tests** — 256KB-response child (pipe-buffer overflow path), silent-child timeout, and closed/foreign-loop reuse guards (56 pass).

Same deadlock family as the CI consolidate self-deadlock fixed in the 3.18 line.

---

Patch release on top of [v3.19.0](https://github.com/cdeust/Cortex/releases/tag/v3.19.0) (memory hygiene + scoring integrity). Full history: <https://github.com/cdeust/Cortex/releases>.
