Skip to content

fix(mothership): a pure resend verdict, and Send-now drops a message the server already has - #8744

Merged
waleedlatif1 merged 4 commits into
stagingfrom
refactor/mothership-resend-verdict
Oct 7, 2026
Merged

waleedlatif1 merged 4 commits into
stagingfrom
refactor/mothership-resend-verdict

Conversation

@waleedlatif1

@waleedlatif1 waleedlatif1 commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Fourth step of the chat send-queue consolidation (after #8743): a pure resend verdict, one discard helper, and Send-now honouring the verdict (G5).

  • A pure resend verdict. resendVerdict(entry, history | null) in send-queue-policy.ts returns 'send' | 'wait' | 'drop':

    • drop when the chat's history shows the reused id accepted (as a user message or as the running turn);
    • wait when the history couldn't be read;
    • otherwise send.

    needsResendCheck decides whether the history has to be read at all. The queue drain acts on the verdict (defer on wait, discard on drop), replacing the side-effecting boolean mustNotResend. acceptedMessageIds moved into the policy module.

  • One discard helper. discardQueuedSend(chatKey, id) replaces the three copies of clear handoff state, clear claim, remove.

  • G5: Send-now honours drop. Send-now skipped the history check, so a message the server had already accepted could be sent again by hand. Once the earlier attempt's claim had expired, that ran a second turn. It now checks first and drops such a message. A history it can't read doesn't hold back a send the user asked for, because the server deduplicates while the claim lasts.

  • Tidy-ups from refactor(mothership): one hold field and one retry field on a queued send #8743's review:

    • rehydrate rows for the production shape and for a queue already in the new shape;
    • the offline-hold waits in the DOM tests check hold === 'online';
    • the one-lookup comment names where the one-hop migration invariant is enforced.

Release note: rollback

A build older than #8743 ignores hold and retry when it restores a saved queue. After a rollback, a tab that reloads could drain a held message right away instead of waiting for the user, the network, or its retry delay. Duplicates are still covered: such a message keeps admissionUnknown and its reused id, so it can't be edited into a second message and the server deduplicates it while the claim lasts.

Type of Change

  • Bug fix
  • Improvement (refactor)

Testing

  • drops a Send-now whose id the server already accepted instead of resending it (DOM) fails on staging: one POST goes out. It passes here.
  • resendVerdict unit tests: no check needed, drop (message or running turn), send, and wait.
  • The own-id 409 test from fix(mothership): decide once whether a queued send may already be on the server #8727 now reaches its branch through a Send-now restored from its stored handoff. With G5, a message whose earlier attempt is the running turn is dropped before any POST. It still fails without the own-id check.
  • does not stop the running turn for a Send-now removed while its history is read (DOM): after its history read, Send-now goes on only if the message is still this view's queued, unedited, undispatched message. Fails without that check.
  • Rehydrate test: the production shape (retryRequired: false) and the new shape pass through as expected.
  • The full gate and integration tests ran on the CI runner.

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)

…Send-now honours it

- resendVerdict(entry, history | null) returns send, wait or drop, and the
  queue drain acts on it, instead of a boolean check with side effects
- discardQueuedSend replaces the three copies of clear handoff, clear claim,
  remove
- Send-now checks the history too and drops a message the server already
  accepted instead of resending it (G5); a history it cannot read does not
  hold back a send the user asked for
- the own-id conflict test reaches that branch through a restored Send-now,
  since a message the history shows accepted is now dropped first
- rehydrate rows for the production shape (retryRequired: false, no hold)
  and for a queue already in the new shape
- the offline-hold waits check hold === 'online' instead of any hold
- the one-lookup comment names where the one-hop invariant is enforced
@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 1:43pm UTC

Request Review

@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 6 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 message deduplication logic in the send queue.

The PR appears safe to merge, with no outstanding findings.

What we checked:

  • Send-now stops the wrong turn: sendQueuedMessageImmediately checks the current chat, mount, dispatch owner, editor, and queue after reading history. It returns before stopGeneration when the message is no longer eligible.

Summary

The PR moves resend decisions into resendVerdict, shares queue cleanup through discardQueuedSend, and makes Send-now drop messages already accepted by the server.

  • Changes since the last review rename the verdict callback and add three tests for competing sends, navigation, and unmounting.
  • No new actionable issues or confirmed rule violations were found.
  • The earlier unnumbered finding is fixed: Send-now checks that the message still exists before calling stopGeneration.
  • Tests were inspected, not run.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Queued message] --> B{Resend verdict}
  B -->|drop| C[Remove queued send and handoff state]
  B -->|send| D[Dispatch message]
  B -->|wait| E{Send-now?}
  E -->|No| F[Delay automatic retry]
  E -->|Yes| G[Check current chat, mount, queue and dispatch owner]
  G -->|Still eligible| D
  G -->|No longer eligible| H[Return without stopping the turn]
Loading

Reviews (3) · Last reviewed commit: "test(mothership): cover Send-now's re-ch..." · Reviewed by Greptile

Comment thread apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts Outdated
…ng its history read

Send-now reads the chat's history before stopping the running turn. A
message removed, edited or dispatched in that time, or a view that moved on,
still stopped the turn. It now re-reads the queue and checks the chat and
mount are current before going on.
@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 6 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

Send-now no longer stops a turn in a chat the user moved to during the
read, or from a surface that unmounted during it, and leaves a message
the drain dispatched meanwhile to that dispatch. applyHeldResend is
renamed applyResendVerdict.
@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 6 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 00b6cee into staging Oct 7, 2026
35 checks passed
@waleedlatif1
waleedlatif1 deleted the refactor/mothership-resend-verdict branch October 7, 2026 16:32

This branch was previously deployed

1 inactive deployment
Preview — cb91ded8 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