fix: stop previous TTS queue on reconnect - #7
Conversation
Default clawgo run rebuilds the TTS queue after every hello-ok. The loop ranges a never-closed channel, so each bridge drop leaks a goroutine. Stop the previous queue before starting the next one, and stop the last queue when run returns. Signed-off-by: Sebastien Tardif <[email protected]>
|
🦞👀 Pull request received. I will update this pull request when review starts. |
|
Codex review: needs changes before merge. Reviewed September 2, 2026, 2:09 PM ET / 18:09 UTC. ClawSweeper reviewWhat this changesThe PR replaces the local text-to-speech queue after each successful bridge reconnect and adds a test that an idle prior worker exits. Merge readinessKeep open: the patch stops idle prior queue loops but cannot stop speech already running during a reconnect. Likely related people: Mariano Belinky, feature-history contributor (medium confidence). Priority: P2 Review scores
Verification
How this fits together
flowchart LR
A[Gateway bridge] --> B[Reconnect loop]
B --> C[Chat subscription]
C --> D[TTS queue]
D --> E[System speech process]
B --> F[Replace prior queue]
F --> D
E --> G[Audio output]
Before merge
Findings
Agent review detailsSecurityNone. Review metrics
Merge-risk optionsMaintainer options:
Copy recommended automerge instructionTechnical reviewBest possible solution: Carry queue shutdown into the active system speech process, then demonstrate that reconnect terminates an in-flight prior worker before the replacement queue proceeds. Do we have a high-confidence way to reproduce the issue? Yes: the supplied real reconnect trace targets the former default-branch revision, and current main has not changed the affected command source. Source confirms that an active Is this the best way to solve the issue? No: the patch repairs idle queue workers but not an active speech call; shutdown must reach the subprocess to fulfill the queue-replacement lifecycle. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: not found in the target repository. Codex review notes: model internal, reasoning high; reviewed against c6e46796a1c8. LabelsLabel justifications:
EvidenceAcceptance criteria:
What I checked:
Likely related people:
Rank-up movesOptional improvements that raise the rating; they are not merge blockers.
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (9 earlier review cycles; latest 8 shown)
|
What Problem This Solves
Default
clawgo run(-chat-subscribe true,-tts-engine system) builds a TTS queue after everyhello-ok. The queue loop ranges a channel that is never closed. A bridge drop reconnects, starts a second queue, and leaves the first goroutine ranging forever.Each later drop adds another leaked loop. On a flaky Raspberry Pi or Linux link this grows without bound until
clawgo runis killed.This PR stops the previous queue before starting the next one after reconnect, and stops the last queue when
runreturns. Introduced inf601408(2026-01-04) and present for 237 days. Related reconnect work: #5, #6.Evidence
Before (binary from
upstream/mainat5f1b9d9). Fake bridge accepts, sendshello-ok, then drops. Two drops, third session, then SIGQUIT. ThreeTTSQueue.loopgoroutines still ranging:After (this patch). Same fake bridge and two drops. One loop remains (the current session):
Reconnect helper without
Stopleft the old loop ranging. WithStopit exited:Real behavior proof
Behavior or issue addressed: Bridge reconnect no longer leaves the previous TTS queue goroutine ranging a never-closed channel.
Real environment tested: macOS 26.6.2 (Darwin 25.6.0 arm64), go1.27.0, clawgo built from this branch at
/tmp/oc-pr-clawgo-F003. Compared against a binary built fromupstream/main(5f1b9d9).Exact steps or command run after this patch: Started a local TCP bridge that replies
hello-okand then drops the socket. Wrote a state file with a token so pairing is skipped. Ranclawgo run -bridge 127.0.0.1:$PORT -mdns=false -tts-engine system -tts-system-command /usr/bin/true. After three hello-ok sessions (two reconnects), sent SIGQUIT and countedmain.(*TTSQueue).loopstacks. Also rango test ./cmd/clawgo -run TestReplaceTTSQueueStopsPreviousLoop -count=1 -timeout 15s -vbefore and after callingStopon the previous queue.Evidence after fix: terminal output from the patched binary:
The unfixed binary after the same two reconnects:
Observed result after fix: After two bridge drops, the patched
clawgo runhad oneTTSQueue.loopgoroutine. The unfixed binary had three, one per hello-ok.What was not tested: Live TTS against a real OpenClaw gateway and
espeak-ngaudio output. The leak is the ranging loop, not the speak binary./usr/bin/truewas used as-tts-system-commandsoLookPathsucceeds on this host.Command: live
clawgo runagainst a dropping TCP bridge, then SIGQUIT. Alsogo test ./cmd/clawgo -run TestReplaceTTSQueueStopsPreviousLoop -count=1 -timeout 15s -v.Observed: unfixed binary, 3
TTSQueue.loopstacks after two reconnects. Patched binary, 1 stack. Red step failed at 2.00s (previous TTS queue still ranging after reconnect). Green step passed at 0.00s.Expected: each reconnect stops the previous queue so only the current session loop remains.
Time: 11:29:13 PDT
Date: 2026-08-29
Environment: macOS 26.6.2, Darwin 25.6.0 arm64, go1.27.0 darwin/arm64