You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(channels): overlapping loadChannels() — an older response can overwrite the newer region's list #154
Overlapping loadChannels() calls can render the wrong region's channel list: the response that lands last wins, not the request that was made last. Pre-existing on master; found while reviewing #153 (it does not make it worse).
Reproduction (seen in a browser against a local server)
On #/channels, select region SJC and delay the /api/channels?region=SJC response by ~2.5 s.
Before it returns, switch to SFO.
The SFO response arrives first and renders; then the delayed SJC response arrives and replaces the list.
The region filter shows SFO, but the sidebar shows the SJC set.
loadChannels() in public/channels.js (around line 1856) has no request generation; every caller (RegionFilter.onChange around line 1014, the show-encrypted toggle, shared-channel approval, init()) awaits api('/channels' + qs) and writes channels unconditionally.
Proposed fix
A request token like the existing messageRequestId / beginMessageRequest() / isStaleMessageRequest() pattern (around lines 179–245): bump a channelsRequestId when loadChannels() starts, and drop the response (no render, no reconcile) if a newer request has started meanwhile. Keep it compatible with #153's client-state merge (sample the WS sequence for the request that actually renders).
Acceptance criteria
Delayed older response + newer region change: the newer region's list is rendered and stays.
No extra /channels request per change; existing callers unchanged.
Unit test with controlled api() timing, plus a Playwright check with a delayed route.
loadChannels() stamps each request with a generation (channelsRequestId), following the messageRequestId pattern. When a newer request has started, an older response is dropped, both on success and on error: it is neither rendered nor reconciled. No extra /channels request is made, and the #153 client-state merge is kept. A unit test with controlled api() timing and a Playwright test with a delayed route cover it.
Activity
test(e2e): open channels by their name in the #154/#155 E2E (#225 rev…
Merge pull request #225 from dborup/codex/issue-154-155-channels-race…
dborup commentedon Oct 5, 2026
Fixed by #225 (merged as
aff158c7).loadChannels()stamps each request with a generation (channelsRequestId), following themessageRequestIdpattern. When a newer request has started, an older response is dropped, both on success and on error: it is neither rendered nor reconciled. No extra/channelsrequest is made, and the #153 client-state merge is kept. A unit test with controlledapi()timing and a Playwright test with a delayed route cover it.