Surfaced in #12340. Two WS handshake conventions coexist: websocket_endpoint/ws/npu-workers (websockets.py) close(4001) BEFORE accept() (per #2818 — returns HTTP 403 on auth fail), while live_events.py does accept() THEN close() (returns 101 + close frame). The close-before-accept form makes an auth-rejected WS indistinguishable from a missing route (403) — which caused the #12340 misdiagnosis. Owner decision: standardize on ONE convention (accept-before-close = clearer client errors / fail-loud, but reverses #2818's deliberate close-before-accept). Reconcile deliberately across all WS handlers. Refs #12340 #2818 #1408.
Surfaced in #12340. Two WS handshake conventions coexist:
websocket_endpoint/ws/npu-workers(websockets.py)close(4001)BEFOREaccept()(per #2818 — returns HTTP 403 on auth fail), whilelive_events.pydoesaccept()THENclose()(returns 101 + close frame). The close-before-accept form makes an auth-rejected WS indistinguishable from a missing route (403) — which caused the #12340 misdiagnosis. Owner decision: standardize on ONE convention (accept-before-close = clearer client errors / fail-loud, but reverses #2818's deliberate close-before-accept). Reconcile deliberately across all WS handlers. Refs #12340 #2818 #1408.