87d03cf8c6
The stdio reader ran inline under the transport lock, and bufio never observes a context. A server that accepted a request and then wrote nothing held that lock forever. alive() takes the same lock and Refresh calls alive() while holding the manager lock, so one mute python server wedged Tools, Status and every Call, including turns that touch no MCP tool at all. The read now runs on its own goroutine feeding a channel, the call selects on the context, and a call that gives up drops the connection so the manager re-dials. The frame bound was measured after the line had been assembled, which is not a bound. A server emitting 500 MB with no newline had all 500 MB in mavend before the check could reject it, which on the deploy target is an OOM kill of the core daemon. The scanner's own buffer limit enforces it now. The HTTP transport never checked the response id. A server request sent mid-stream, sampling/createMessage or roots/list, unmarshalled into a response with neither result nor error, so the call reported success with an empty string. The act was logged as done and the tool never ran. The id must match and the frame must carry a result or an error. Found in review of #70.