Summary
WebSocket replay disambiguates same-path sessions by the handshake query string (added in the v0.8.1 replay-repeatability work — see wsReplayer.takeForPath / filterByQuery in internal/proxy/websocket.go). That comparison is exact: s.Request.Query == query. Unlike HTTP request bodies and paths, the WS query is not run through the configured IgnoreRules.
Why it matters
This is the same class of problem that pushed us off VCR: the moment a realtime handshake query carries per-run noise — a workspace_id, session token, or timestamp, all plausible for /v1/realtime — exact matching breaks. With the current filter-with-fallback shape it won't 599 (it degrades to path-only cyclic matching), but it loses the query-based disambiguation precisely when a path has multiple distinct sessions, reintroducing the per-run churn we're migrating away from.
Why it's not urgent (yet)
- No WS upstreams in the test suite today.
- The only realtime handshake query in practice is
?model=…, which is stable across runs.
So today exact matching is correct. We want to close the gap before realtime lands, not after it bites.
Proposed fix
Extend matcher.IgnoreRule's In: target to accept request.query (alongside the existing request.body / request.path), and run the WS handshake query through the same normalization pipeline HTTP bodies and paths already use. Cheap to do when the rule schema is next touched.
- Add an
IgnoreInQuery = "request.query" constant.
- Apply matching query rules in the WS replayer (it will need access to the configured rules — currently
wsReplayer has none).
- Optionally fold query normalization into HTTP matching too, for symmetry (HTTP currently ignores query entirely — confirm that's still intended).
References
internal/proxy/websocket.go — takeForPath, filterByQuery
internal/matcher/matcher.go — IgnoreRule, signature
Summary
WebSocket replay disambiguates same-path sessions by the handshake query string (added in the v0.8.1 replay-repeatability work — see
wsReplayer.takeForPath/filterByQueryininternal/proxy/websocket.go). That comparison is exact:s.Request.Query == query. Unlike HTTP request bodies and paths, the WS query is not run through the configuredIgnoreRules.Why it matters
This is the same class of problem that pushed us off VCR: the moment a realtime handshake query carries per-run noise — a
workspace_id, session token, or timestamp, all plausible for/v1/realtime— exact matching breaks. With the current filter-with-fallback shape it won't 599 (it degrades to path-only cyclic matching), but it loses the query-based disambiguation precisely when a path has multiple distinct sessions, reintroducing the per-run churn we're migrating away from.Why it's not urgent (yet)
?model=…, which is stable across runs.So today exact matching is correct. We want to close the gap before realtime lands, not after it bites.
Proposed fix
Extend
matcher.IgnoreRule'sIn:target to acceptrequest.query(alongside the existingrequest.body/request.path), and run the WS handshake query through the same normalization pipeline HTTP bodies and paths already use. Cheap to do when the rule schema is next touched.IgnoreInQuery = "request.query"constant.wsReplayerhas none).References
internal/proxy/websocket.go—takeForPath,filterByQueryinternal/matcher/matcher.go—IgnoreRule,signature