stop asking what was playing, and say what the socket is doing

Two things.

The music now-playing restore is disabled on the web. The music sidecar is not running on
every machine that serves this app, so every page load fired /music/now-playing and logged a
503 in the console of a browser that was not there for music. Restoring a paused track is a
nicety; a permanent error on every load of every screen is not. The player is untouched — it
simply no longer asks what WAS playing.

And the chat socket now logs its own lifecycle: create, open, close with code and whether it
was stale or tearing down, every message received, and every message sent or queued with the
socket readyState. window.__officerWs = false turns it off.

This is instrumentation I should have added two rounds ago. A pane connects and then sits
silent, and I have now reasoned from this hook source three times without explaining it — the
browser says a socket closed and never says who closed it or whether the message left. The
handover doc says instrument before theorising and I did not follow my own note.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-10 22:33:56 +01:00
co-authored by Claude Opus 5
parent bcb3d6d621
commit cb7ab55cca
2 changed files with 29 additions and 1 deletions
+20 -1
View File
@@ -43,10 +43,19 @@ export const useChatWebSocket = ({ url, onMessage, onOpen }: UseChatWebSocketPar
const socket = new WebSocket(url);
socketRef.current = socket;
// Temporary, and deliberately loud. A pane connected and then sat silent, and reasoning from this
// hook's source three times running did not explain it — the console says a socket closed, never who
// closed it or whether the message went out. `window.__officerWs = false` turns it off.
const host = new URL(url).host;
const log = (what: string, extra?: unknown) =>
(window as any).__officerWs !== false && console.log(`[ws ${host}] ${what}`, extra ?? '');
log('creating');
socket.addEventListener('open', () => {
if (socketRef.current !== socket) return;
setIsConnected(true);
retryRef.current = 0;
log('OPEN');
// BEFORE onOpen, deliberately: onOpen sends the resume/attach handshake, and anything the user
// typed while connecting belongs after that, not in front of it.
const queued = pendingRef.current;
@@ -57,6 +66,7 @@ export const useChatWebSocket = ({ url, onMessage, onOpen }: UseChatWebSocketPar
socket.addEventListener('message', (ev) => {
try {
log('recv', String(ev.data).slice(0, 120));
const data = JSON.parse(typeof ev.data === 'string' ? ev.data : new TextDecoder().decode(ev.data));
onMessageRef.current(data);
} catch {
@@ -64,7 +74,13 @@ export const useChatWebSocket = ({ url, onMessage, onOpen }: UseChatWebSocketPar
}
});
socket.addEventListener('close', () => {
socket.addEventListener('close', (ev) => {
log('close', {
code: ev.code,
reason: ev.reason,
stale: socketRef.current !== socket,
tearingDown: isCleaningUpRef.current,
});
if (isCleaningUpRef.current) return;
if (socketRef.current !== socket) return;
setIsConnected(false);
@@ -123,9 +139,12 @@ export const useChatWebSocket = ({ url, onMessage, onOpen }: UseChatWebSocketPar
const socket = socketRef.current;
const message = JSON.stringify(data);
if (socket && socket.readyState === WebSocket.OPEN) {
if ((window as any).__officerWs !== false) console.log(`[ws ${new URL(url).host}] send`, message.slice(0, 120));
socket.send(message);
return;
}
if ((window as any).__officerWs !== false)
console.log(`[ws ${new URL(url).host}] QUEUED (socket ${socket?.readyState ?? 'none'})`, message.slice(0, 80));
// Not open yet, or reconnecting. Hold it rather than dropping it — see `pendingRef`. Bounded so a
// socket that never comes back cannot grow this without limit; the oldest go first, because the
// newest message is the one the user is still waiting on.
@@ -119,7 +119,16 @@ export const MusicPlayerHost = () => {
// Restore the saved "currently playing" on first load — paused, at its position — so a reload/return
// lands back on the track. Skipped when a queue already exists (an in-app nav kept player state).
//
// DISABLED on the web (Andre, 2026-08-10). The music sidecar is not running on every machine that
// serves this app, so every page load fired `/music/now-playing` and logged a 503 in the console of a
// browser that was not there for music at all. Restoring a paused track is a nicety; a permanent error
// on every load of every screen is not worth it. The player itself is untouched — play something and
// it works; it simply no longer asks what WAS playing.
const RESTORE_NOW_PLAYING = false;
useEffect(() => {
if (!RESTORE_NOW_PLAYING) return;
if (restoredRef.current) return;
restoredRef.current = true;
if (queue.length) return;