fix(poll): make the poll question visible both directions (echo out, backfill in)#155
fix(poll): make the poll question visible both directions (echo out, backfill in)#155omarshahine wants to merge 6 commits into
Conversation
|
Codex review: needs maintainer review before merge. Reviewed July 5, 2026, 12:52 PM ET / 16:52 UTC. Summary Reproducibility: yes. from source and contributor proof: current main sends only the poll payload and only enriches vote rows, while the PR head sends a caption and backfills native poll questions. I did not run Messages locally in this read-only review. Review metrics: 2 noteworthy metrics.
Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Maintainer decision needed
Security Review detailsBest possible solution: Land the focused caption/backfill fix after maintainer acceptance of the two-message poll-send behavior, then use #157 for the skill-doc follow-up. Do we have a high-confidence way to reproduce the issue? Yes from source and contributor proof: current main sends only the poll payload and only enriches vote rows, while the PR head sends a caption and backfills native poll questions. I did not run Messages locally in this read-only review. Is this the best way to solve the issue? Yes, with maintainer acceptance of the delivery tradeoff. The implementation is narrow, keeps caption echo best-effort to avoid duplicate poll retries, and constrains inbound backfill to native caption-shaped rows with regression coverage. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 9ac97ab1d242. Label changesLabel changes:
Label justifications:
Evidence reviewedWhat I checked:
Likely related people:
What the crustacean ranks mean
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
Review history (8 earlier review cycles)
|
Messages never renders the poll title (payload item.title) on the poll balloon — only the options are shown. Agent-created polls therefore arrived as bare options with no visible question. Native polls carry the question in a separate comment message whose reply_to is the poll guid (the "comment or Send" composer field), which imsg never populated. Both `poll send` (CLI) and the `poll.send` RPC now echo `--question` as a reply comment on the poll after creation, matching native behavior. Callers pass only the question and the visible caption appears for free, so agents (e.g. OpenClaw) need no change. `--comment` overrides the echoed text; the poll payload title is still set for agent readback. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The echoed caption was sent with selectedMessageGuid, which builds a full threaded reply (thread_originator + associated_message_type 100) and makes Messages decorate the poll balloon with a reply-connector line. Native poll comments carry NO thread metadata (reply_to only, type 0), rendering as a clean caption. Send the caption as a plain message right after the poll instead. Outbound (from_me) rows are cached and never re-processed by the monitor, so the poll<->comment link was never needed on our own sends; inbound user polls still carry native reply_to for folding. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The inverse of the outbound echo. Native poll balloons have no title (item.title empty), so an inbound native poll decoded from chat.db had question=nil and rendered to agents as a title-less "Poll — options: …". The question is carried in the poll's caption — a separate message whose reply_to_guid is the poll guid. enrichedPollEvent now backfills an empty created-poll question from that caption (earliest reply-to-the-poll message, decoded via decodeMessageRow for the attributedBody fallback). imsg-created polls that already carry a title are unchanged; vote enrichment is untouched. Verified against chat.db: native polls that were question=None now surface "Favorite crustacean friend of a Lobster?", "What color pill?", etc. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
f5de557 to
2847415
Compare
Two CI failures surfaced once this branch ran CI for the first time: - pollCommentText hardcoded WHERE m.reply_to_guid, which throws on older or synthetic message tables that omit the column. Gate it on schema.hasReplyToGUIDColumn (mirroring MessageRowSelection) so a created poll with no caption column degrades to nil instead of failing the pull. - The question echo adds a second .sendMessage bridge call, which clobbered the single-capture mocks in the poll-send tests. Record all calls and assert both the .sendPoll and the .sendMessage caption echo. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dTDUtxanzs8NDhTD862QV
If the poll delivered but the follow-up caption send throws, the CLI must not exit nonzero — a retry would send a duplicate poll. Wrap the echo in do/catch and report on stderr, matching handlePollSend. Closes the last ClawSweeper P2 on this branch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dTDUtxanzs8NDhTD862QV
|
@clawsweeper re-review Addressed all three P2 findings and added real behavior proof:
Proof (PR body updated): live |
|
🦞🧹 I asked ClawSweeper to review this item again. |
The poll caption echo, --comment override, and inbound question backfill live in openclaw#155, not on main (shipped imsg 0.12.2 'poll --help' has no --comment). Drop those claims so the skill documents only shipped behavior and can merge independently of openclaw#155. Tracked by openclaw#157 to re-add once openclaw#155 lands. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dTDUtxanzs8NDhTD862QV
ClawSweeper P1: pollCommentText matched any reply_to_guid row, so a threaded inline reply to the poll (associated_message_type 100, thread originator set) could be mistaken for the poll question. Filter to clean native captions (type 0, no thread originator), schema-aware since both columns are optional. Adds regression coverage: a clean caption still backfills; a threaded reply is ignored and the question stays empty. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011dTDUtxanzs8NDhTD862QV
|
Fixed the P1 (64ab396): @clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
Drop the poll caption echo, --comment override, and inbound question backfill from the imsg skill: those live in imsg PR openclaw/imsg#155, not shipped imsg 0.12.2 (poll --help exposes only --question/--option). Also removes the inaccurate 'reply comment whose reply_to is the poll guid' framing — #155 sends the caption as a plain message, not a reply. Keeps shipped poll send/vote usage. Re-add once a release ships #155.
* docs: tailor imsg skill for OpenClaw agents * docs(imsg-skill): document that poll send echoes --question as a visible comment * docs(imsg-skill): note inbound native poll question is backfilled from its caption * docs(imsg-skill): document only shipped poll behavior Drop the poll caption echo, --comment override, and inbound question backfill from the imsg skill: those live in imsg PR openclaw/imsg#155, not shipped imsg 0.12.2 (poll --help exposes only --question/--option). Also removes the inaccurate 'reply comment whose reply_to is the poll guid' framing — #155 sends the caption as a plain message, not a reply. Keeps shipped poll send/vote usage. Re-add once a release ships #155. --------- Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>
What Problem This Solves
Native iMessage poll balloons have no title —
item.titleis empty and Messages never renders it. The question you see on a native poll lives in a separate caption message whosereply_tois the poll guid (the composer's "comment or Send" field). imsg ignored this on both sides:poll send --question 'X'storedXin the invisibleitem.title, so agent-created polls rendered as bare options with no question.chat.dbhadquestion=nil, so agents saw a title-lessPoll — options: ….Why This Change Was Made
Make the poll question visible in both directions, matching native behavior, with no consumer changes required (OpenClaw already renders
📊 Poll: <question>when the field is present, and passes--questionon send).User Impact
poll send/poll.sendRPC now send--questionas a plain caption message right after the poll —associated_message_type = 0,thread_originator_guid = None, i.e. not a threaded reply, so it renders as a normal caption bubble instead of the "reply connector" a threaded reply would draw.--commentoverrides the echoed text; the echo is best-effort so a caption failure never fails an already-delivered poll. Agents keep passing only--question.enrichedPollEventbackfills an empty created-poll question from its caption (earliest reply-to-the-poll message), so inbound native polls surface their question. imsg-created polls with a real title are unchanged; vote enrichment untouched.Evidence
Verified end-to-end on macOS 26 through a live v2 bridge, sending with this branch's build (
swift build --product imsg).Outbound — live send to a test group:
Visual — confirmed in the Messages UI on the receiving device: the poll shows the three options (Lobster / Crab / Shrimp), and directly beneath it the question appears as an ordinary caption bubble ("PR#155 proof: which crustacean?") — no threaded-reply connector line. (Screenshot available; can be attached to this PR.)
Structural proof (chat.db) — my sent caption is byte-for-byte the same shape as a natively-composed poll's caption, and differs from the earlier threaded-reply attempt that drew the connector:
Note: this bridge auto-populates
reply_to_guidon every send (the poll itself got areply_toalthough no--reply-towas passed), so both native and PR captions carryreply_to; the connector is driven bythread_originator/assoc_type=100, which the PR caption does not set — matching native exactly.Inbound — backfill via
imsg history(chat.db read, no bridge), native[recv]polls that decoded asquestion=Nonenow surface their question:Review follow-ups addressed (ClawSweeper P2s): CLI caption echo is now best-effort (
do/catch, matching the RPC path);pollCommentTextis guarded onschema.hasReplyToGUIDColumnso schemas without the column degrade to nil instead of throwing; poll-send tests record the full bridge call sequence and assert both.sendPolland the.sendMessagecaption echo. macOS + Linux CI green.🤖 Generated with Claude Code