Summary
Three symptoms traced to the same root cause: session_turn_mutation_transport_unavailable — the local-to-cloud session mutation sync layer fails silently and never recovers, producing zombie sessions, duplicate responses, and an unmanageable session list.
Related: #272 (stale transcript on open) — likely the same transport failure from the reader's side.
Environment
- Happier CLI:
0.2.10-dev.83 (dev channel)
- Platform: Linux (aarch64, Ubuntu 24.04)
- Connection: stable (Codex sessions on the same machine have zero issues)
Symptoms
1. Zombie sessions — alive process, dead UI
Sessions stay "alive" (process running, claude child process present) but become completely unresponsive in the UI. Their logs freeze at a single line:
[API] Authoritative session mutation remains queued and is blocking later mutations
mutationKind: "session_turn"
deliveryStatus: "retryable"
reason: "session_turn_mutation_transport_unavailable"
At time of investigation, 6 out of 7 active dev-channel sessions were in this state, with log ages ranging from 7 to 39 hours. These sessions cannot be stopped or archived from the UI — they just sit in the list indefinitely.
2. Duplicate responses
The same assistant response renders multiple times in the UI. Mechanism from logs:
- A completed turn's mutation fails to deliver (server returns HTTP 404)
- Client marks it
retryable and retries indefinitely
- Worst case observed: 11,970 attempts over 4.2 days for a single mutation
- When transport briefly recovers, the queued mutations flush in bulk
- UI receives and renders multiple copies of the same turn
Evidence from daemon log:
mutationId: "daemon-observed-exit:b686a332..."
attempts: 11970
ageMs: 362319353 (4.2 days)
deliveryDiagnostic.http.status: 404
3. Dead session records never cleaned up
When the daemon restarts (e.g. --takeover on self-update), it sends SIGTERM to child sessions. Some sessions are not reattached by the new daemon:
[DAEMON RUN] Startup reattach alive marker scan finished {aliveMarkerCount: 2}
[DAEMON RUN] Reattached 2 sessions from disk markers
But if 4 sessions were tracked before the restart, the other 2 become orphans: process dead, no exit log written, but their daemon-sessions.dev/pid-*.json record persists forever. The UI shows them as sessions that can't be stopped or archived.
4. UI regression — sorting and swipe gestures removed
Previously available features that helped work around the above issues are now gone:
- Sorting (could push unresponsive sessions to the bottom)
- Swipe-left to close/archive (quick way to dismiss dead sessions)
Without these, the only way to clean up is manually deleting files from ~/.happier/tmp/daemon-sessions.dev/.
Root cause analysis
The session_turn_mutation_transport_unavailable error indicates the HTTP transport to api.happier.dev returns 404 for session mutations. This affects 71% of all session logs (44 out of 62) on this machine, suggesting a systematic issue rather than transient network failure.
The daemon log also shows:
[WARN] Connected-service quota policy remains disabled because startup hydration failed
error: "Failed to list connected service auth groups (404)"
This 404 from the /v3/connect/claude-subscription/groups endpoint may be related — if the server doesn't recognize the session/subscription, mutations would also fail.
Key architectural difference vs Codex: Codex has no "every turn must sync to a remote state machine" layer. Its sessions are purely local (process + .jsonl), so none of these failure modes exist.
Steps to reproduce
- Start multiple sessions via Happier dev channel
- Use them normally for a few hours
- Observe that older sessions' logs freeze at the
mutation_transport_unavailable message
- Try to interact with those sessions in the UI — no response
- Try to stop or archive them — no effect
- Open a session after transport reconnects — same response may appear multiple times
Expected behavior
- Transport failures should have a bounded retry with backoff, not infinite retry
- After N failures, the mutation should be dropped or the session marked as degraded (local-only mode)
- Dead sessions (process gone) should be reaped automatically, not left as permanent UI ghosts
- Sorting and swipe-to-dismiss should be available for manual cleanup
Suggested fixes
- Bounded retry + circuit breaker for session mutations — stop after N attempts, fall back to local-only
- Periodic liveness scan in the daemon — check if tracked session PIDs are still alive, remove dead records
- Idempotent mutation delivery — deduplicate on the server side to prevent duplicate rendering even if retried
- Restore sort and swipe gestures in the session list UI
Summary
Three symptoms traced to the same root cause:
session_turn_mutation_transport_unavailable— the local-to-cloud session mutation sync layer fails silently and never recovers, producing zombie sessions, duplicate responses, and an unmanageable session list.Related: #272 (stale transcript on open) — likely the same transport failure from the reader's side.
Environment
0.2.10-dev.83(dev channel)Symptoms
1. Zombie sessions — alive process, dead UI
Sessions stay "alive" (process running, claude child process present) but become completely unresponsive in the UI. Their logs freeze at a single line:
At time of investigation, 6 out of 7 active dev-channel sessions were in this state, with log ages ranging from 7 to 39 hours. These sessions cannot be stopped or archived from the UI — they just sit in the list indefinitely.
2. Duplicate responses
The same assistant response renders multiple times in the UI. Mechanism from logs:
retryableand retries indefinitelyEvidence from daemon log:
3. Dead session records never cleaned up
When the daemon restarts (e.g.
--takeoveron self-update), it sends SIGTERM to child sessions. Some sessions are not reattached by the new daemon:But if 4 sessions were tracked before the restart, the other 2 become orphans: process dead, no exit log written, but their
daemon-sessions.dev/pid-*.jsonrecord persists forever. The UI shows them as sessions that can't be stopped or archived.4. UI regression — sorting and swipe gestures removed
Previously available features that helped work around the above issues are now gone:
Without these, the only way to clean up is manually deleting files from
~/.happier/tmp/daemon-sessions.dev/.Root cause analysis
The
session_turn_mutation_transport_unavailableerror indicates the HTTP transport toapi.happier.devreturns 404 for session mutations. This affects 71% of all session logs (44 out of 62) on this machine, suggesting a systematic issue rather than transient network failure.The daemon log also shows:
This 404 from the
/v3/connect/claude-subscription/groupsendpoint may be related — if the server doesn't recognize the session/subscription, mutations would also fail.Key architectural difference vs Codex: Codex has no "every turn must sync to a remote state machine" layer. Its sessions are purely local (process +
.jsonl), so none of these failure modes exist.Steps to reproduce
mutation_transport_unavailablemessageExpected behavior
Suggested fixes