The panel needs live transitions, so add ONE in-process publisher
(api/events.py, installed on app.state.publisher in the lifespan) and
a GET /api/v1/panel/events SSE route on the panel router — it inherits
the single require_panel_token check. The complete route now builds
the event through the core builder and publishes it only when the
core's .appended flag says an actual transition happened; a no-op
re-complete publishes nothing. Tests stream from a real uvicorn
instance on an ephemeral port because httpx's ASGITransport buffers
endless SSE bodies.