fix(slack-stream): always deliver fallback on streaming failure regardless of orphan deletion

When a streaming append/start call fails and chat.delete also fails, the
stream message is left in 'streaming' state — never finalized via
chat.stopStream, which may render as invisible or broken on mobile Slack.
streamSession.stopped is already set to true so the end-of-dispatch
finalizer also skips the stream, leaving the payload with no recovery path.

Remove the orphanDeleted guard from the deliverWithStreaming catch block:
always call deliverNormally here even if deletion failed, to ensure the user
receives the complete answer. A cosmetic duplicate on desktop clients is
preferable to a silently truncated answer.

The guard is intentionally kept in the finalizer catch: there the stream
message has already been fully finalized (all content visible), so skipping
deliverNormally on deletion failure avoids a true content duplicate.
This commit is contained in:
Nora 2026-03-10 05:06:33 +00:00 committed by Vincent Koc
parent c9fbb445a7
commit d8e1aff7ee

View File

@ -335,13 +335,18 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
// Re-deliver the full content: everything already in the stream message
// plus the current payload that failed to append. Using only `payload`
// here would drop all previously-streamed text.
if (orphanDeleted) {
const fallbackText = streamedText ? `${streamedText}\n${text}` : text;
await deliverNormally(
{ ...payload, text: fallbackText },
streamSession?.threadTs ?? plannedThreadTs,
);
}
//
// Note: we deliver even when orphan deletion failed. The stream message
// is stuck in "streaming" state (never finalized via chat.stopStream)
// and may not render on mobile Slack — skipping deliverNormally here
// would silently drop content with no later recovery path (the
// finalizer is skipped because streamSession.stopped is already true).
// A cosmetic duplicate on desktop is preferable to a truncated answer.
const fallbackText = streamedText ? `${streamedText}\n${text}` : text;
await deliverNormally(
{ ...payload, text: fallbackText },
streamSession?.threadTs ?? plannedThreadTs,
);
}
};