fix(ui): chat send failures were invisible when the session pane was …
fix(ui): chat send failures were invisible when the session pane was hidden (#124473) * fix(ui): always surface terminal chat send failures Terminal chat send failures were recorded only on the queue item when the owning pane was not visible (reconnect, alias drift, split-pane routing), so the operator saw nothing at all — an action ending in silence. Root cause: every error surface in the send/drain path was gated on visibleSessionMatches(...), and the FIFO outbox drain treated every chat.history reconcile rejection as a silent retryable "blocked", so a non-retryable rejection (e.g. auth loss) wedged the head — and everything behind it — permanently with no visible outcome. Fix, at the owner: - New surfaceChatDeliveryFailure() in steer-lifecycle.ts (the shared error-text owner): visible pane keeps the inline chat error; otherwise the failure routes through the existing global toast host, naming the session. All terminal failure sites in chat-send-delivery, chat-outbox-drain, chat-send-queue-state, and steer-lifecycle now use it. - reconcileStoredChatOutboxHead: a non-retryable GatewayRequestError on the head now terminally fails a never-attempted head (unblocking the lane) or parks an attempted head as unconfirmed — both with a visible outcome — instead of blocking the lane forever. - Composer disabled-reason: the reason now also renders while a draft hides the placeholder, and the cloud-startup-pending gate gets a reason instead of a silently disabled composer. Regression tests: hidden-pane terminal failure surfaces via toast; wedged head fails visibly and the lane drains the next message; attempted head parks unconfirmed; disabled reason visible with draft text present. * fix(ci): raise startup JS baseline for global failure surfacing and pin workspace-sync test clock The chat send path now imports session-display naming for the global failure toast, adding ~1 KiB gzip to startup JS (335452 B on CI's Linux builder, still well under the 358400 B committed cap). workspace-sync "never commands" asserted the exact dispatch timeoutMs (777) but the impl derives it from a Date.now() deadline, so any elapsed ms between admission and dispatch failed the exact-equality assertion on a loaded runner. Pin the clock like the sibling timeout tests do. * fix(ui): surface route-switched command failures and agent-scope global toast naming ClawSweeper review findings on #124473: - A queued local command failing after the operator navigated away hit failCommand(error) with expose=false; the dispatcher's stale-scope guard had already withheld the inline error, so a successful state write recorded the failure invisibly — the silent class this PR removes. Expose it globally when the scope is stale and the owning pane is hidden; a stale scope with the pane still visible keeps the failed queue chip (the new connection owns the inline surface). - Global session rows are agent-scoped behind one shared "global" key, so the toast row lookup could borrow another agent's label. Match the row's agentId to the failed outbox's agent for global keys. Both regression tests fail pre-fix (stash-verified).
评论
?
参与讨论