The Coach chat route had three identical `new ReadableStream({
start(controller) { try { ... } finally { controller.close(); } } })`
blocks (refusal / provider-error / happy path), differing only in
which frames they enqueued. Extract the boilerplate into
`src/lib/sse/create-stream.ts` so the v1.5 iOS streaming endpoints
inherit the same try/finally close semantics without copy-paste.
The helper accepts sync or async emit callbacks; the controller is
always closed in `finally` so a thrown emit never hangs the response.
Three unit tests pin the sync, async, and throw paths.
Closes Sr-H2.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>