Skip to content

A queued message whose send failed says why, and one cut off goes again - #49

Merged
fxck merged 4 commits into
mainfrom
fix/queued-held
Oct 1, 2026
Merged

fxck merged 4 commits into
mainfrom
fix/queued-held

Conversation

@fxck

@fxck fxck commented Oct 1, 2026

Copy link
Copy Markdown
Member

On a Mate (Milo), a turn ended and the follow-up queued under it was never sent.

The cause. A queued message lives in the tab and goes out when the turn ends. If that send failed at that moment (the account check timing out, the link dropping, a refusal), the message was put back held. A held message:

  • never went out again on its own;
  • blocked everything queued behind it;
  • looked exactly like a waiting one: only the clock's tooltip changed, and the reason showed in the top banner, or nowhere if the send was cut off.

Now:

  • A send that was cut off goes back in the queue unheld and is retried automatically, at most 3 times. Each retry carries the first attempt's message and command ids, so a command the server already accepted is deduped by its command receipts (OrchestrationEngine.ts) and can never start a second turn.
  • A refused send is held with its reason, shown on its bubble in place of the clock. ↑ becomes Retry, which mints fresh ids. The top banner no longer repeats the reason.
  • Messages behind a held one say "Waits for the message above".
  • While a question or approval is open, the next message says "Waits for your answer above", and its ↑ is disabled with that tooltip rather than doing nothing.

Tests:

  • queuedMessageStore tables cover a held reason, the never-due rule, Retry clearing the hold and the ids kept across a requeue.
  • queuedSendOutcome covers 9 cases, and queuedSendAttemptIds 3.
  • A harness at /design-queued.html shows the bubble's states.

🤖 Generated with Claude Code

fxck added 4 commits October 1, 2026 02:42
… with its reason

A queued follow-up whose send failed for a moment as its turn ended was held for good:
any failure put it back waiting for Send now, and it looked exactly like one still
waiting. A send interrupted — the link dropped, the command cut off, the account's
access still being read past its wait — now goes back unheld for the queue to send
once the link and the gates allow, up to three times. A send refused with words is held
with them, for its bubble to say rather than the banner over the conversation; Retry
lifts the hold before it sends.
A held send looked exactly like one waiting; only the clock's tooltip changed. The held
bubble now says its send's reason in the clock's place, one line in the error tone,
and its ↑ becomes Retry. A message queued behind a held one says it waits for it. The
next one, while a question or an approval waits on the person, says "Waits for your
answer above", and its ↑ waits too, saying so, instead of a press that did nothing.
/design-queued.html draws a queued follow-up waiting, held with its reason, behind a held
one, and the next while a question waits on the person, side by side at one width.
…ame ids

An interrupted send may have reached the server before its answer was lost, and its
automatic retry minted a new message and command id, starting a second turn with the
same words. A queued send now settles its ids before it goes; one sent back after an
interruption keeps them, and the retry goes with them, which the server's command
receipts take once. A person's Retry after a refusal goes with fresh ids, so a refusal
remembered by id never comes back.
@fxck
fxck merged commit 8c469fc into main Oct 1, 2026
11 checks passed
fxck added a commit that referenced this pull request Oct 1, 2026
- #48 Run card tests unmount what they draw
- #49 A queued message whose send failed says why, and one cut off goes again
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