Skip to content

Coalesce Apple URL-preview split-sends into a single notification #141

@omarshahine

Description

@omarshahine

Summary

Apple delivers a URL-preview "split-send" as two chat.db rows: the user's text row (e.g. Dump https://example.com) and a separate URLBalloonProvider preview row, arriving ~0.8–2.0s apart. Consumers that want this as one logical message (e.g. OpenClaw) currently have to debounce and merge client-side, which is imprecise (you can't structurally tell a split-send from two separate sends without the balloon marker) and adds latency to every DM.

Now that imsg exposes balloon_bundle_id (#137), imsg has the structural signal to coalesce these rows at the source and emit a single logical message — removing the need for any client-side debounce/merge.

Proposal

When imsg surfaces messages (watch notifications and history/search reads), coalesce an Apple URL-preview balloon row into its originating text row so consumers receive one message instead of two:

  • Detect the com.apple.messages.URLBalloonProvider balloon row.
  • Associate it with the immediately preceding same-chat / same-sender text row it previews.
  • Emit a single coalesced message (preserve the text row's GUID for reply threading; annotate/attach the preview as appropriate).
  • Apply consistently across watch, messages, and searchMessages so all read paths agree.

Why imsg, not the client

  • imsg owns the chat.db read path and already has balloon_bundle_id plus GUID/threading context — it's the natural owner of "un-splitting" Apple's split-send.
  • Removes per-consumer reimplementation. OpenClaw currently does this in a debouncer that holds every DM for 2.5s so the preview row can arrive (see fix(imessage): gate split-send coalescing on imsg metadata openclaw#90858).
  • Eliminates the consumer-side latency tradeoff and the "did this build emit the field?" compatibility branching.
  • Single source of truth: one logical message, structurally derived, not timing-guessed.

Context / related

Acceptance criteria

  • A Dump https://example.com split-send is emitted as one message across watch / history / search.
  • Two genuinely separate same-sender sends are NOT coalesced.
  • Reply threading (GUID) and timestamps remain correct on the coalesced message.
  • Tests cover: URL split-send coalesced; non-URL balloons (polls, etc.) untouched; separate sends untouched.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal priority bug or improvement with limited blast radius.clawsweeper:needs-live-reproClawSweeper needs live local, crabbox, or manual validation to confirm this issue.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.impact:message-lossThis issue is about lost, duplicated, misrouted, or suppressed channel messages.issue-rating: 🐚 platinum hermitGood issue quality with a plausible reproduction path needing some confirmation.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions