Skip to content

feat: expose message balloon bundle metadata#137

Merged
steipete merged 2 commits into
openclaw:mainfrom
omarshahine:fix/expose-imessage-balloon-metadata
Jun 10, 2026
Merged

feat: expose message balloon bundle metadata#137
steipete merged 2 commits into
openclaw:mainfrom
omarshahine:fix/expose-imessage-balloon-metadata

Conversation

@omarshahine

@omarshahine omarshahine commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Expose the raw Messages message.balloon_bundle_id value in the stable Message JSON/RPC payload as balloon_bundle_id.

This gives downstream consumers a structural signal for URL/link-preview balloon rows, especially com.apple.messages.URLBalloonProvider, instead of forcing them to infer split-send payloads from user-authored text such as short command lead-ins.

Details

  • Carry balloon_bundle_id from SQLite row decoding into IMsgCore.Message.
  • Encode the field in CLI JSON, messages.history, watch.subscribe, and search payloads.
  • Keep upstream Polls decoding intact while exposing the same decoded source column publicly.
  • Document the new additive Message field in docs/json.md.
  • Add fixture coverage for history/search row decoding and watch JSON output.
  • Addressed Codex auto-review finding that searchMessages() initially dropped the decoded balloon metadata.

Verification

Rebased on current openclaw/main (041b40686a6dde88efabb2e401792c24b5093675); GitHub now reports the PR as mergeable at head e223709a91e81f3d405a9a8593eafdc3b6ec0e24.

  • swift build
  • swift format lint Sources/IMsgCore/Models.swift Sources/IMsgCore/MessageStore+Messages.swift Sources/IMsgCore/MessageStore+Search.swift Sources/imsg/OutputModels.swift Tests/IMsgCoreTests/MessageStoreTests.swift Tests/imsgTests/WatchCommandTests.swift
  • DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer swift test --filter MessageStoreTests passed: 19 tests.
  • DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer swift test --filter WatchCommandTests passed: 6 tests.
  • DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer make test passed: 325 tests.

Real local Messages DB proof, redacted to only row id and structural metadata:

  • DB precheck: SELECT COUNT(*) FROM message WHERE balloon_bundle_id='com.apple.messages.URLBalloonProvider'; observed 8 rows; latest joined proof row observed chat_id=3, ROWID=5855.
  • CLI history:
    ./.build/debug/imsg history --chat-id 3 --limit 100 --json | jq -c 'select(has("balloon_bundle_id")) | {id, has_balloon_bundle_id: has("balloon_bundle_id"), balloon_bundle_id}'
    observed {"id":5855,"has_balloon_bundle_id":true,"balloon_bundle_id":"com.apple.messages.URLBalloonProvider"}
  • RPC messages.history:
    printf ... | ./.build/debug/imsg rpc | jq -c '.result.messages[] | select(has("balloon_bundle_id")) | {id, has_balloon_bundle_id: has("balloon_bundle_id"), balloon_bundle_id}'
    observed {"id":5855,"has_balloon_bundle_id":true,"balloon_bundle_id":"com.apple.messages.URLBalloonProvider"}
  • RPC watch.subscribe replay from cursor:
    printf ... since_rowid=5854 ... | ./.build/debug/imsg rpc | jq -c 'select(.method=="message") | .params.message | select(has("balloon_bundle_id")) | {id, has_balloon_bundle_id: has("balloon_bundle_id"), balloon_bundle_id}' | head -1
    observed {"id":5855,"has_balloon_bundle_id":true,"balloon_bundle_id":"com.apple.messages.URLBalloonProvider"}

@clawsweeper

clawsweeper Bot commented Jun 6, 2026

Copy link
Copy Markdown

Codex review: needs maintainer review before merge. Reviewed June 6, 2026, 2:25 PM ET / 18:25 UTC.

Summary
The PR carries message.balloon_bundle_id from row decoding into IMsgCore.Message and JSON/RPC MessagePayloads, with docs and fixture tests for history, search, and watch output.

Reproducibility: not applicable. this is an additive metadata exposure rather than a broken existing behavior report. The PR nevertheless includes a concrete after-fix local DB proof path for history, RPC history, and watch replay.

Review metrics: 2 noteworthy metrics.

  • Public payload surface: 1 nullable field added. A new stable JSON/RPC message field needs maintainer API acceptance even though it is additive.
  • Diff size: 7 files changed, 69 additions, 1 deletion. The change is small and spans core decoding, CLI/RPC output, docs, and focused tests.

Merge readiness
Overall: 🦞 diamond lobster
Proof: 🦞 diamond lobster
Patch quality: 🦞 diamond lobster
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Risk before merge

  • [P1] This adds a stable JSON/RPC field backed by raw Apple Messages metadata, so the remaining decision is whether maintainers want that public API surface.

Maintainer options:

  1. Decide the mitigation before merge
    Merge the focused additive field if maintainers accept exposing raw balloon bundle identifiers as stable message metadata.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge

  • No automated repair is needed; a maintainer should decide whether to accept the additive stable JSON/RPC field and merge if normal checks pass.

Security
Cleared: The diff only exposes an already-read message metadata column and updates tests/docs; I found no concrete security or supply-chain regression.

Review details

Best possible solution:

Merge the focused additive field if maintainers accept exposing raw balloon bundle identifiers as stable message metadata.

Do we have a high-confidence way to reproduce the issue?

Not applicable: this is an additive metadata exposure rather than a broken existing behavior report. The PR nevertheless includes a concrete after-fix local DB proof path for history, RPC history, and watch replay.

Is this the best way to solve the issue?

Yes, subject to maintainer API acceptance: reusing the already selected balloon_bundle_id column and the existing MessagePayload encoder is the narrowest maintainable path I found.

AGENTS.md: found and applied where relevant.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 041b40686a6d.

Label changes

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR body/comment include redacted terminal output from a real local Messages DB showing the new field in CLI history, RPC history, and watch replay.
  • add rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body/comment include redacted terminal output from a real local Messages DB showing the new field in CLI history, RPC history, and watch replay.
  • remove rating: 🌊 off-meta tidepool: Current PR rating is rating: 🦞 diamond lobster, so this older rating label is no longer current.

Label justifications:

  • P3: This is a low-risk additive metadata feature with tests and proof, not an urgent regression or availability issue.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body/comment include redacted terminal output from a real local Messages DB showing the new field in CLI history, RPC history, and watch replay.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body/comment include redacted terminal output from a real local Messages DB showing the new field in CLI history, RPC history, and watch replay.
Evidence reviewed

What I checked:

  • Repository policy read: AGENTS.md was present and fully read; its guidance to keep changes focused and add regression tests for parsing/filtering metadata was applied to this review. (AGENTS.md:1, 041b40686a6d)
  • Current main reads but does not retain balloon metadata: Current main reads columns.balloonBundleID for Polls/dedup logic, but the returned DecodedMessageRow omits that value, so downstream public payloads cannot expose it today. (Sources/IMsgCore/MessageStore+Messages.swift:464, 041b40686a6d)
  • Current public Message model lacks the field: Message currently exposes destinationCallerID and poll but has no balloonBundleID property or initializer parameter on main. (Sources/IMsgCore/Models.swift:317, 041b40686a6d)
  • Current JSON payload/docs lack the field: MessagePayload and docs/json.md do not currently list or encode balloon_bundle_id, confirming the requested public surface remains missing on main. (Sources/imsg/OutputModels.swift:79, 041b40686a6d)
  • PR diff is focused and additive: The PR adds nullable balloonBundleID plumbing through decoded rows, Message, MessagePayload, docs, and fixture expectations for history/search/watch without unrelated churn. (e223709a91e8)
  • Real behavior proof is present: The PR body and follow-up comment include redacted local Messages DB proof showing CLI history, RPC messages.history, and RPC watch.subscribe emitting balloon_bundle_id for a URL balloon row. (e223709a91e8)

Likely related people:

  • Peter Steinberger: Current-main blame across message decoding, public model, JSON output, and docs points to the v0.11.0 imported release commit; the checkout history is shallow, so confidence is limited to available provenance. (role: current area contributor; confidence: medium; commits: c3205e1361bf; files: Sources/IMsgCore/MessageStore+Messages.swift, Sources/IMsgCore/Models.swift, Sources/imsg/OutputModels.swift)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added the proof: sufficient Contributor real behavior proof is sufficient. label Jun 6, 2026
@omarshahine omarshahine force-pushed the fix/expose-imessage-balloon-metadata branch from 76ab0a2 to 0fc650b Compare June 6, 2026 05:13
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jun 6, 2026
@omarshahine omarshahine marked this pull request as ready for review June 6, 2026 05:13
@clawsweeper clawsweeper Bot added P3 Low-risk cleanup, docs, polish, ergonomics, or speculative feature. rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. and removed proof: sufficient Contributor real behavior proof is sufficient. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jun 6, 2026
@omarshahine omarshahine force-pushed the fix/expose-imessage-balloon-metadata branch from 0fc650b to e223709 Compare June 6, 2026 18:19
@omarshahine

Copy link
Copy Markdown
Contributor Author

Rebased this PR onto current openclaw/main (041b40686a6dde88efabb2e401792c24b5093675) and pushed head e223709a91e81f3d405a9a8593eafdc3b6ec0e24; GitHub now reports it as mergeable.

Proof run after the rebase:

  • swift build
  • swift format lint Sources/IMsgCore/Models.swift Sources/IMsgCore/MessageStore+Messages.swift Sources/IMsgCore/MessageStore+Search.swift Sources/imsg/OutputModels.swift Tests/IMsgCoreTests/MessageStoreTests.swift Tests/imsgTests/WatchCommandTests.swift
  • DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer swift test --filter MessageStoreTests passed: 19 tests.
  • DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer swift test --filter WatchCommandTests passed: 6 tests.
  • DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer make test passed: 325 tests.

Real local Messages DB proof was redacted to row id and structural metadata only. The local DB had 8 com.apple.messages.URLBalloonProvider rows; latest joined proof row was chat_id=3, ROWID=5855.

  • CLI history observed {"id":5855,"has_balloon_bundle_id":true,"balloon_bundle_id":"com.apple.messages.URLBalloonProvider"}.
  • RPC messages.history observed {"id":5855,"has_balloon_bundle_id":true,"balloon_bundle_id":"com.apple.messages.URLBalloonProvider"}.
  • RPC watch.subscribe replay from since_rowid=5854 observed {"id":5855,"has_balloon_bundle_id":true,"balloon_bundle_id":"com.apple.messages.URLBalloonProvider"}.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 6, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. labels Jun 6, 2026
omarshahine added a commit to openclaw/openclaw that referenced this pull request Jun 8, 2026
…th back-compat (#90858)

Gate iMessage same-sender DM split-send coalescing on imsg's structural
`balloon_bundle_id` URL-balloon marker (openclaw/imsg#137) instead of timing/
text-shape inference, with a session capability latch and a back-compat path:

- URL-balloon marker present -> merge (precise split-send).
- Build known to emit balloon metadata (session latch) -> keep non-marker
  buckets separate (the precision win).
- Build that never emits balloon metadata (older imsg) -> preserve the legacy
  unconditional merge, so split-send users do not regress to two turns.

Never merges more than shipped main already did. Verified live end-to-end: the
patched gateway, watching a real chat.db via an imsg #137 build, merged a real
iPhone-sent `Dump <url>` split-send into one turn. Client-side removal once imsg
coalesces upstream is tracked in #91243 (openclaw/imsg#141).

Closes #90795
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jun 8, 2026
…th back-compat (openclaw#90858)

Gate iMessage same-sender DM split-send coalescing on imsg's structural
`balloon_bundle_id` URL-balloon marker (openclaw/imsg#137) instead of timing/
text-shape inference, with a session capability latch and a back-compat path:

- URL-balloon marker present -> merge (precise split-send).
- Build known to emit balloon metadata (session latch) -> keep non-marker
  buckets separate (the precision win).
- Build that never emits balloon metadata (older imsg) -> preserve the legacy
  unconditional merge, so split-send users do not regress to two turns.

Never merges more than shipped main already did. Verified live end-to-end: the
patched gateway, watching a real chat.db via an imsg openclaw#137 build, merged a real
iPhone-sent `Dump <url>` split-send into one turn. Client-side removal once imsg
coalesces upstream is tracked in openclaw#91243 (openclaw/imsg#141).

Closes openclaw#90795
@steipete steipete force-pushed the fix/expose-imessage-balloon-metadata branch from e223709 to 54a4196 Compare June 10, 2026 07:52
@steipete

Copy link
Copy Markdown
Collaborator

Maintainer pass on PR #137 complete.

Changes added during maintainer pass:

Proof:

  • make lint passed. Existing warnings only; no serious lint failures.
  • make test passed: 326 tests.
  • /Users/steipete/Projects/agent-skills/skills/autoreview/scripts/autoreview --mode branch --base main reported clean: no accepted/actionable findings.
  • CI on pushed head 54a4196930c49d8cc93c570854f5631d080335c4 is green: linux-read-core and macos passed.

API decision: accepting the additive nullable balloon_bundle_id JSON/RPC field. It exposes an already-read Messages metadata column and leaves absent/empty values omitted as nil.

@steipete steipete merged commit e1972ef into openclaw:main Jun 10, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P3 Low-risk cleanup, docs, polish, ergonomics, or speculative feature. proof: sufficient Contributor real behavior proof is sufficient. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants