Skip to content

fix(mothership): close a pre-aborted SSE stream, keep the new-chat effort across a failed first send - #8754

Merged
waleedlatif1 merged 2 commits into
stagingfrom
fix/sim-review-findings
Oct 7, 2026
Merged

waleedlatif1 merged 2 commits into
stagingfrom
fix/sim-review-findings

Conversation

@waleedlatif1

@waleedlatif1 waleedlatif1 commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Three findings from the #8748 release review.

  • A pre-aborted SSE request no longer subscribes. createSSEStream adds its abort listener inside start(), and that listener never fires for a signal that's already aborted. A client that left while the route was still authorizing got a stream that subscribed anyway and held its handler, timers and a revalidate query every 30 s until rotation (~16.5 min). start() now closes at once with aborted before taking any subscription. Covers all three callers: the desktop inbox stream, mothership events and createWorkspaceSSE.
  • The new-chat effort survives a failed first send. ModelSelector cleared the pick on unmount whenever it had no chat id. A first send swaps the empty-state composer for the chat view, so the pick was wiped mid-send: the chat view showed the default while pending, and once rollbackOptimisticSend restored the pick, the swapped-back composer's unmount wiped it again. The pick belongs to the chatless surface, not one composer, so useChat now owns its lifetime: it drops when the surface unmounts, switches chats, or adopts a chat (adoptResolvedChatId, so a first send stopped before admission doesn't carry it into the next new chat). Admission still moves it onto the new chat via adoptNewChatEffort first. The rollbackOptimisticSend restore is gone: nothing clears the pick while a send is pending, and it overwrote a pick made in the chat view during the send. Covers every useChat surface: Home, organization home and the workflow copilot panel.
  • effort is optional on the chat response. It was required, so during a deploy's traffic shift a new client hitting an old server failed contract validation and the chat didn't load. parseChatHistory already maps a missing value to null; MothershipChatHistory is unchanged.

Type of Change

  • Bug fix

Testing

Each new test fails on staging:

  • never subscribes when the request aborted before the stream started (sse-endpoint.test.ts): expected false to be true, the body never finishes.
  • keeps the new-chat effort across the composer swap of a first send that fails (use-chat.dom.test.tsx, renders the real ModelSelector in a Home-shaped swap): expected 'High' to be 'Low' while pending, and with that line removed, expected null to be 'low' after the failure.
  • keeps a new-chat effort picked while the first send is pending when that send fails: expected 'Low' to be 'Medium' with the rollback restore.
  • starts the next new chat at the default after a first send stopped before admission: expected 'Low' to be 'High' without the adoption clear.
  • drops an unsent new-chat effort when the surface leaves the page / opens another chat pins the remaining abandonment paths on the new layer.
  • loads a chat from a server that predates the effort field (mothership-chats.test.ts): Response failed contract validation — chat.effort.

apps/sim typecheck, biome, check:api-validation, check:api-contract-routes, check:openapi, check:comment-hygiene, check:test-patterns and the home, hooks/queries, contracts and sse-endpoint suites (1031 tests) pass.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

…fort across a failed first send

- createSSEStream closes at once when the request aborted before start(), instead of subscribing until rotation.
- The new-chat effort pick is dropped by useChat when its chatless surface is left, not by each composer's unmount, so a failed first send keeps it and the pending chat view shows it.
- The chat response's effort is optional, so a new client loads chats from a server that predates it.
@vercel

vercel Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
docs Skipped Skipped Oct 7, 2026 6:41pm UTC

Request Review

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 8 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Turn on auto-fix | Re-trigger cubic

@greptile-apps

greptile-apps Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

[Medium risk] Fixes chat stream cleanup and effort state handling across composer transitions.

The PR appears safe to merge; no blocking issue was found.

What we checked:

  • Admitted chats keep the pick: The send saves the pick under the admitted chat’s ID before the surface clears the new-chat value.

Summary

This PR closes already-aborted SSE requests, keeps the new-chat effort through a failed first send, and lets clients load chat responses without effort.

  • The latest changes clear the unused pick when the surface adopts a chat.
  • Rollback now leaves the current pick alone.
  • Tests cover changing the pick during a pending send and stopping before admission.
  • No new actionable issues were found.

Reviews (2) · Last reviewed commit: "fix(mothership): drop the new-chat effor..." · Reviewed by Greptile

A first send stopped before admission adopted its chat without moving the pick, so the next new chat on the same Home mount showed and sent it. adoptResolvedChatId now drops the pick when the surface leaves the new chat. The rollback restore is gone: nothing clears the pick while a send is pending, and it overwrote a pick made during the send.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 8 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Turn on auto-fix | Re-trigger cubic

@waleedlatif1
waleedlatif1 merged commit 69d9ac6 into staging Oct 7, 2026
35 of 36 checks passed
@waleedlatif1
waleedlatif1 deleted the fix/sim-review-findings branch October 7, 2026 19:19

This branch was previously deployed

1 inactive deployment
Preview — 9eb580bd Deployed Oct 7, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant