Log why a voice call ended on the Mac

Merged
CH
20d ago
+285-62

Why

A planning voice call dropped mid-sentence after ~204s. The service's session-ended line shows the Mac's host sent session.close up its sideband (one frame, 74 bytes), no idle report, finalization confirmed. So something on the desktop ended the call, and nothing on the desktop logs which path it was.

What it logs

Both lines go through Effect.logInfo in LiveSessionHolder, which the host's reporterLayer routes to the reporter the desktop writes to stderr. That is the terminal ./scripts/run.sh was started from.

  • One line per ended session, from #tearDown, which every end passes through:
    voice call ended: cause=<LIVE_SESSION_END_CAUSE> [peer_reason=<LIVE_PEER_END_REASON>] close_reason=<reason> session=<id> planning=<bool> seconds=<n>
    • cause is the first hand that decided the end: plan_switched / plan_left (from endPlanCall: PLANNING_OPEN/START to another plan, or PLANNING_CLOSE and sign-out reset), hang_up (the renderer's end act), voice_changed (the voice-setting side effect), drain, replaced (a new offer while a session stood), peer_closed / peer_failed (the renderer's transport report), service_closed (an unasked session.closed), sideband_lost.
  • One line per peer transport report: voice transport: state=<state> [peer_reason=...] session=<id|none> planning=<bool>. This puts the peer connection's connecting/connected/disconnected/failed changes before a drop on record.

To make the renderer's side readable in the same place, the closed-transport report the renderer already sends from LiveCall#tearDown now carries an optional reason (LIVE_PEER_END_REASON in @sidecar/gateway): hung_up, close_timed_out, service_closed, channel_closed, transport_failed, start_timed_out. The schema is voiceReportLiveTransportParamsSchema, and the act, IPC, and gateway method pass it through unchanged. The renderer does not log to the console itself, because a renderer's console does not reach the run.sh terminal.

The lines carry no transcript words, plan contents, tokens, or credentials. They carry fixed reasons, the provider's session id, a boolean, and a number of seconds.

Tests

  • live-session-holder.test.ts: a new test reads the lines off a test Logger layer under TestClock. It covers a planning call ended by a plan switch at 204s, a desk call ended by the peer's channel_closed transport report, and a sideband drop.
  • live-call.test.ts: the existing teardown tests now also assert which reason each end reports: failed transport, answered hang-up, hang-up timeout, and dropped channel.

./scripts/check.sh exits 0 on Linux.

CI could not verify the Mac, and ./scripts/verify.sh was not run (it needs a Mac). CI builds nothing for the Mac, so this change needs a developer's own verify.sh run before it can be called Mac-verified.

šŸ¤– Generated with Claude Code