-
Notifications
You must be signed in to change notification settings - Fork 758
Description
Summary
The HTTP/WebSocket transport path (PluginHub) does not respect retry_on_reload=False and lacks the stale connection detection that the stdio path now has. This means script mutations sent via HTTP clients (Claude Code, Cursor, etc.) can be retried during domain reload, causing duplicate execution — the same class of bug fixed for stdio in PR #792.
Root Cause
send_with_unity_instance() discards all kwargs (including retry_on_reload) when routing through the HTTP path. It extracts command_type and params, then calls PluginHub.send_command_for_instance() which has no knowledge of retry semantics.
# unity_transport.py — HTTP branch
command_type = args[0]
params = args[1] if len(args) > 1 else kwargs.get("params")
# ... retry_on_reload is silently dropped
raw = await PluginHub.send_command_for_instance(unity_instance, command_type, params)Specific Issues
| Issue | Stdio (fixed) | HTTP (broken) |
|---|---|---|
| Stale connection detection before send | _ensure_live_connection() MSG_PEEK |
None — detected only via 30s timeout |
retry_on_reload=False respected |
Yes | No — silently dropped |
| Reconnect wait during mutations | Skipped when retry_on_reload=False |
Always waits 20s for session reconnect |
| Duplicate mutation risk | Low | High |
| Connection-lost verification | SHA comparison after reconnect | Timeout → client may retry blindly |
Suggested Fix
-
Pass
retry_on_reloadthrough the HTTP path —PluginHub.send_command_for_instance()should accept and respect it. When False, skip_resolve_session_id()wait and don't retry on disconnect. -
Add pre-send connection validation — equivalent to stdio's
_ensure_live_connection(), probe WebSocket liveness before sending mutations. -
Unify the transport retry contract — Both stdio and HTTP paths implement their own retry/reconnect/reload-wait logic independently, which means every fix has to be applied twice and debugged twice. Consider extracting a shared
TransportPolicyor similar abstraction that both paths use:- Stale connection detection (pre-send health check)
- Reload-aware retry semantics (
retry_on_reloadflag) - Post-mutation wait-for-ready
- Connection-lost-after-send detection
This doesn't need to be a deep abstraction — even a shared set of helper functions that both paths call at the right points would prevent the current situation where stdio gets a fix and HTTP silently remains broken.
Context
Discovered during PR #792 (fix script edit tools retrying non-idempotent commands during reload). The stdio path was fixed end-to-end; this issue tracks the equivalent work for HTTP.