Repository navigation
fix(mothership): a pure resend verdict, and Send-now drops a message the server already has - #8744
Conversation
…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
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
|
@cubic-dev-ai review this PR |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
|
…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.
|
@cubic-dev-ai review this PR |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
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.
|
@cubic-dev-ai review this PR |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
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)insend-queue-policy.tsreturns'send' | 'wait' | 'drop':dropwhen the chat's history shows the reused id accepted (as a user message or as the running turn);waitwhen the history couldn't be read;send.needsResendCheckdecides whether the history has to be read at all. The queue drain acts on the verdict (defer onwait, discard ondrop), replacing the side-effecting booleanmustNotResend.acceptedMessageIdsmoved 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:
hold === 'online';Release note: rollback
A build older than #8743 ignores
holdandretrywhen 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 keepsadmissionUnknownand 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
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.resendVerdictunit tests: no check needed, drop (message or running turn), send, and wait.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.retryRequired: false) and the new shape pass through as expected.Checklist