test: pin agent WebSocket supersede and close-code handling#441
Open
eric-descourtis-thenvoi wants to merge 1 commit into
Open
Conversation
Cross-repo follow-up from thenvoi/thenvoi-platform#2328 (finding M8): since Phoenix 1.8 the platform closes evicted agent sockets with WebSocket close code 1001, which phoenix.js-style clients treat as reconnect-expected — the opposite of the terminal supersession contract (supersede push carries retryable: false). Verified the SDK already complies, and pins that behavior with tests driving the real PHXChannelsClient supervisor against an in-process fake Phoenix server: - supersede push is terminal regardless of the observed close code (server closes 1011 after the push; no reconnect) - missed supersede push + eviction close 1001 does not reconnect (literal 1001 pin, mirroring the platform-side close-code pin) - abnormal codeless close without the push still reconnects — the accepted worst case, bounded platform-side by re-supersession and reconnect rate limiting - the default ReconnectPolicy classification the SDK relies on (1000/1001 terminal, None/1006 retryable) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Cross-repo follow-up from thenvoi/thenvoi-platform#2328 (finding M8).
Context
Since Phoenix 1.8, the platform closes evicted (superseded) agent sockets with WebSocket close code 1001, which phoenix.js-style clients read as reconnect-expected — the opposite of the platform's terminal supersession contract: the
agent_controlsupersedepush carriesretryable: falseand SDKs must not auto-reconnect (spec/websocket-api.draft.md). The platform side already pins the literal 1001 (agent_presence_phoenix_disconnect_test.exs) and documents the contract in the evictor moduledoc; this PR is the SDK-side verification + pins.Verification result: the SDK already complies
BandLink._on_supersede→WebSocketClient.record_terminal_disconnect→PHXChannelsClient.auto_reconnect = False. The supervisor checksauto_reconnectbefore any close-code classification, so the push is authoritative regardless of the close code observed afterwards._drain_topic_queue) → close code 1001 is classified together with 1000 as do-not-reconnect under the defaultReconnectPolicy(reconnect_on_normal_close=False), whichWebSocketClientuses unmodified. The Python client does not have the phoenix.js 1001-reconnect behavior.Tests added (
tests/websocket/test_close_code_handling.py)All four drive the real
PHXChannelsClientsupervisor against an in-process fake Phoenix V2 server (no mocks of the reconnect loop):ReconnectPolicyclassification pin: 1000/1001 terminal,None/1006 retryableMutation-verified: ignoring the supersede push, or replacing the 1001 close with 1011, makes the corresponding test fail with the expected assertion.
Test evidence
tests/websocket/— 70 passed--ignore=tests/integration/ --ignore=tests/e2e/semantics): 3349 passed, 168 skipped; the only failures locally aretests/integration/*(need live platform keys) andtests/integrations/acp/test_e2e_codex_acp.py(needs a working codex login) — both pre-existing on cleanmainin the same environment and skipped in CIruff check,ruff format,pyrefly checkcleanRelated
band-ai/fern-javascript-sdk): Fern-generated REST only, no WebSocket client — nothing to verify there.agent_control, reconnects on any close code) — tracked separately.🤖 Generated with Claude Code