Queue undelivered stickers - the bubble already promised it
A sticker to somebody signed out was marked "Undelivered - will send" and then never entered the outbox, so the label was a lie for exactly one content kind. iOS got this fix earlier via a wire field on its outbox entry; Android's queue turned out not to need one - conversations.send transmits its argument as the ratchet plaintext verbatim, and a sticker's wire IS its plaintext, so the existing replay path delivers both kinds once the entry stores the encoded envelope instead of prose. OutboxTest gains the sticker version of the end-to-end promise: queued while they are away, delivered AS A STICKER once a device exists (a real second identity, not a fake bundle), and the bubble restated without turning into text. Six outbox tests green; engine, client and app suites green. ⚠️ The same lie still stands for GROUP sends, text and sticker both: they record PENDING when nobody was reachable and nothing queues them. That needs a thread-aware outbox (per-member retry, a completion rule, restating the group thread) - designed work, not a patch, and it is on the roadmap rather than half-built here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
6a26668d72
commit
a68c9212d9
@@ -236,9 +236,19 @@ class Session(
|
||||
fun sendSticker(peerUserId: Long, pack: String, stickerId: String):
|
||||
Conversations.Sent {
|
||||
val sent = conversations.sendSticker(peerUserId, pack, stickerId)
|
||||
record(Vault.threadForUser(peerUserId), "", mine = true,
|
||||
val at = System.currentTimeMillis()
|
||||
record(Vault.threadForUser(peerUserId), "", mine = true, at = at,
|
||||
sticker = Sticker(pack, stickerId),
|
||||
delivery = if (sent.reachedSomeone) Delivery.DELIVERED else Delivery.PENDING)
|
||||
// 🔴 **Queued, like text — because the bubble already promised it.**
|
||||
// A sticker to somebody signed out was marked "Undelivered — will
|
||||
// send" and then never entered the outbox, so the label was a lie for
|
||||
// exactly one content kind. The queue stores the ratchet plaintext,
|
||||
// and a sticker's wire IS its plaintext, so the same replay path
|
||||
// delivers both.
|
||||
if (!sent.reachedSomeone) {
|
||||
enqueue(peerUserId, io.flamenet.e2e.Content.sticker(pack, stickerId), at)
|
||||
}
|
||||
return sent
|
||||
}
|
||||
|
||||
@@ -326,6 +336,13 @@ class Session(
|
||||
* ⚠️ Which is worth being honest about in the UI: "Sending…" here means
|
||||
* "waiting on your phone", not "in flight".
|
||||
*/
|
||||
/**
|
||||
* ⚠️ `text` is the ratchet PLAINTEXT, not necessarily prose. For a text
|
||||
* message the two are the same string; for a sticker it is the encoded
|
||||
* content envelope. `flushOutbox` replays it through `conversations.send`,
|
||||
* which transmits its argument as the plaintext verbatim — so both kinds
|
||||
* take the same path out.
|
||||
*/
|
||||
private fun enqueue(peerUserId: Long, text: String, at: Long) {
|
||||
val pending = vault.outbox()
|
||||
pending.put(JSONObject()
|
||||
|
||||
Reference in New Issue
Block a user