feat(channels): implement channels.toggle RPC method#1142
Conversation
Implement runtime channel enable/disable via WebSocket API.
Changes:
- Add StartChannel(), StopChannel(), IsChannelRunning() methods to Manager
- Implement handleToggle RPC handler in channels.go
- Support idempotent operations (already_running/already_stopped status)
- Thread-safe with existing mutex protection
- Health status tracking and structured logging
The channels.toggle method allows operators to enable or disable
messaging channels (telegram, discord, etc.) at runtime without
restarting the server. Useful for maintenance, debugging, and
incident response.
API:
Request: {method: channels.toggle, params: {channel: telegram, enabled: false}}
Response: {channel: telegram, enabled: false, status: ok}
Fixes the stub implementation that returned 'not implemented' error.
mrgoonie
left a comment
There was a problem hiding this comment.
Summary: This PR implements the channels.toggle RPC by adding manager-level StartChannel/StopChannel helpers and a WebSocket handler for runtime channel enable/disable.
Risk level: High
Mandatory gates:
- Duplicate/prior implementation: clear
- Project standards: issue found
- Strategic necessity: clear value, but current implementation is not safe to ship
- CI/checks: missing/not reported
Findings: - Critical: none
- Important: StartChannel and StopChannel call channel.Start(ctx) / channel.Stop(ctx) while holding Manager.mu. Several channel Start/Stop implementations perform network calls, spawn goroutines, wait on shutdown, or can block on external services. Holding the global manager mutex across those operations can freeze channels.list/status/health sync and any other manager operation during a slow Telegram/Slack/etc start/stop, and it risks lock-order deadlocks if channel lifecycle code later calls back into manager health/state paths. The manager should resolve the channel under lock, release the lock before running lifecycle I/O, then reacquire only for health map updates or use a per-channel lifecycle guard.
- Important: The PR adds a 245-line CHANNELS_TOGGLE_IMPLEMENTATION.md at repository root. GoClaw’s docs are organized under docs/, and this file reads like an implementation note rather than durable user/operator documentation. Please either move a concise operator-facing doc into the proper docs location or drop it from the PR.
- Important: There are no regression tests for channels.toggle. At minimum add tests for invalid JSON, missing/unknown channel, already-running/already-stopped idempotency, successful start/stop, and the lock behavior around slow Start/Stop so this endpoint does not regress into blocking global channel status.
- Suggestion: Error strings are raw English while the handler already loads locale. Existing handlers use localized protocol errors where practical; user-facing validation messages should follow that pattern.
Verdict: REQUEST_CHANGES
clark-cant
left a comment
There was a problem hiding this comment.
Review: feat(channels): implement channels.toggle RPC method (#1142)
Summary: Implements the channels.toggle WebSocket RPC method to start/stop channels at runtime. Adds StartChannel, StopChannel, IsChannelRunning to the channel manager, and replaces the stub handler in channels.go.
Risk level: Medium — runtime channel lifecycle control is operator-facing infrastructure with security implications.
Mandatory gates
- Duplicate / prior implementation: clear — no duplicate PR or issue found for this exact toggle RPC.
- Project standards: docs found — code follows existing patterns in
manager.goandchannels.go. - Strategic necessity: clear value — runtime channel control is useful for ops, maintenance, and incident response.
Findings
Important:
-
CHANNELS_TOGGLE_IMPLEMENTATION.mdat repo root — This 245-line documentation file does not belong in the repository root. It duplicates what should be inline code comments, API docs indocs/, or a commit message. Remove it from the PR entirely. -
No RBAC / permission check on toggle — The handler only checks that the channel exists. Any authenticated WebSocket client can enable/disable channels. This is operator-level infrastructure control — it should require an explicit permission scope (e.g.
operator.channelsor admin role). The PR body acknowledges this as a future enhancement, but shipping it without any access control is a security gap. -
params.Enabledbool cannot distinguish missing fromfalse—json.Unmarshalinto a plainboolmeans{"channel":"telegram"}(noenabledfield) silently defaults tofalseand stops the channel. Use*boolor a separate validation step to require the field explicitly.
Suggestion:
-
No tests — The PR only confirms it builds. Add at minimum: a unit test for
StartChannel/StopChannelon the manager (channel found, not found, already running/stopped), and a handler-level test for param validation and idempotent responses. -
Idempotent error returns —
StartChannelreturnsfmt.Errorf("channel %q is already running")andStopChannelreturnsfmt.Errorf("channel %q is not running"), but the handler checksIsRunning()before calling them, making these dead-code error paths in normal flow. Consider making the manager methods themselves idempotent (return nil if already in desired state) to simplify callers.
Verdict: Request changes
The core implementation is sound and follows existing patterns, but the documentation file at root, missing RBAC, and bool validation gap need addressing before merge.
Posted by /ck:review-pr at 2026-06-26T06:01:00Z
|
🦸♂️ Maintainer follow-up — This PR has been sitting with CHANGES_REQUESTED for 6 days since reviews from @mrgoonie and myself. Key blockers to address:
@zhihan — are you still planning to iterate on this? Happy to help clarify any of the feedback. If you don't have bandwidth right now, no worries — just let us know so we can manage expectations. 🙏 Posted by github-maintain at 2026-06-26T12:53:00Z |
|
🦸♂️ Maintainer review — This PR implements Current status: BLOCKED — no CI checks have run on this branch, and the merge state is blocked. To move this forward:
Code notes (pending CI):
The feature itself is a good addition — runtime channel toggling for maintenance/debugging is a legitimate operational need. Once CI is green and rebased, I'll do a full code review. Posted by github-maintain at 2026-06-29T17:30:00Z |
Summary
Implements the WebSocket RPC method that allows operators to enable/disable messaging channels at runtime without restarting the server.
Changes
Channel Manager ()
RPC Handler ()
API
Request:
{ "type": "req", "id": "1", "method": "channels.toggle", "params": { "channel": "telegram", "enabled": false } }Response:
{ "type": "res", "id": "1", "result": { "channel": "telegram", "enabled": false, "status": "ok" } }Use Cases
Testing
Notes
Fixes the stub implementation that previously returned 'channels.toggle not implemented' error.