fix(desktop): bound thread /query and surface load errors, not false-empty - #6447
Open
wpfleger96 wants to merge 1 commit into
Open
fix(desktop): bound thread /query and surface load errors, not false-empty#6447wpfleger96 wants to merge 1 commit into
wpfleger96 wants to merge 1 commit into
Conversation
…empty Long threads sometimes never loaded (permanent skeleton) or silently rendered a failed fetch as "No replies in this branch yet". Two defects: - The shared reqwest client sets no timeout, so a stalled/half-open /query HTTP request hangs forever. Add a 30s per-request deadline on both /query builders (scoped per-request, not client-level, because the client also serves STT/TTS downloads, builderlab auth, and the media proxy). Set above the 25s WS history timeout so a slow-but-live relay is not cut off early. Timeouts classify to the stable "relay unreachable: request timed out" string. - ChannelScreen consumed only isPending/data; a terminal error fell through to the empty state with no recovery. Plumb isError + refetch through to MessageThreadPanel and paint an explicit "Couldn't load replies" + Retry card. A pure selectThreadRepliesSurface helper pins the precedence so a terminal error never resolves to empty and cached rows stay visible non-destructively under a later error. To stay under the desktop file-size ratchet, move relay.rs's inline test module to relay/tests.rs and extract the reply empty/error cards (MessageThreadReplyState) and the per-row branch-highlight derivation (selectThreadRowHighlight) out of the panel, each with unit coverage. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.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.
Long threads in the desktop app sometimes never load (stuck on a skeleton until you close and reopen the panel), and a failed load silently renders as "No replies in this branch yet" — presenting a broken fetch as an authoritative empty thread with no way to recover. This fixes both, the two IMPORTANT findings from the thread-load investigation.
Defect 1 — unbounded
/queryrequestThe shared
reqwest::Clientinrelay.rssets no timeout, and neither/queryrequest builder set a per-request.timeout(...). A stalled or half-open connection (headers or body never arrive) leaves the request pending forever, so a thread-history load hangs on the skeleton indefinitely.Fix: a 30s per-request deadline on both
/querybuilders. Scoped per-request rather than client-level because the same client also serves STT/TTS model downloads, builderlab auth, and the media proxy — a client-level timeout would cut those off. The deadline sits above the 25s WSHISTORY_TIMEOUT_MSso a slow-but-live relay isn't cut off before the WebSocket path would be. A timeout surfaces throughclassify_request_erroras the stable"relay unreachable: request timed out"string.Defect 2 — terminal error painted as empty
ChannelScreenconsumed onlyisPending/datafrom the thread-replies query. Once React Query exhausted its one retry,isPendingwas false and the zero-length data fell throughselectDeferredListRenderStateto the"empty"state — indistinguishable from a genuinely empty branch, with no retry affordance.Fix: plumb
isError+refetchthroughChannelScreen→ChannelPane→MessageThreadPanel. A pureselectThreadRepliesSurfacehelper decides the paint in strict precedence — the load-bearing invariant is that a terminal error never resolves to"empty", and cached replies stay visible non-destructively under a later error (the error card only surfaces when there is nothing to show). The panel renders an explicit "Couldn't load replies" + Retry card (testidsmessage-thread-replies-error/message-thread-replies-retry).Tests
stalled_query_request_times_out_with_classified_error— a loopback server that never responds; assertsis_timeout()and the stable classified string.selectThreadRepliesSurface— pending→skeleton, terminal error→error (never empty), page-2 failure never empty, cached rows stay visible under error, successful-empty→empty, retry-success→list, streaming→pending, and huddle-transcript collapse.selectThreadRowHighlight— branch-range membership, direct-child, and guide-suppression cases for the extracted highlight helper.Structure
To stay under the desktop file-size ratchet (both
relay.rsandMessageThreadPanel.tsxwere one line under the 1000-line ceiling),relay.rs's inline test module moved torelay/tests.rs, and two pure pieces were extracted from the panel: the empty/error reply cards (MessageThreadReplyState) and the per-row branch-highlight derivation (selectThreadRowHighlight).