Skip to content

Preserve legacy watch resume semantics for GUID-linked URL previews #184

Description

@omarshahine

Problem

PR #181 reproduced a Messages.app URL-preview variant where one composition creates a text row and a GUID-linked preview row, but imsg watch emits two logical events. The repaired head, 5d86702043da, passed maintainer review and CI. The PR closed without merging because its watcher hardening changed the documented resume contract.

Peter summarized the remaining work in his closing comment:

Closing after binary maintainer review. The bug is real and the repaired head is CI-clean, but it changes the documented watch resume contract from id to a new physical cursor. Exact-head delayed-preview reconnect proof for both legacy id and cursor is also unavailable because the signed CLI is blocked in this host's Contacts/TCC preflight.

Landing therefore requires an owner decision on legacy id compatibility plus exact-head resume proof. We do not leave contributor PRs in a change-request limbo; the decision brief and repair SHA are preserved for a future focused implementation.

Existing consumers persist a watch event's id and pass it back through --since-rowid. A folded URL-preview event can span the text row and a later physical preview row, so resuming from the logical text-row id must not replay the preview or create a second delivery.

Proposed plan

  1. Start from the reviewed repair at 5d86702043da and retain its structurally constrained GUID-linked URL-preview coalescing.
  2. Preserve id as a backward-compatible --since-rowid input. Resolve a folded event's physical completion boundary inside the watcher so legacy clients neither replay the preview row nor skip the next logical message.
  3. Keep cursor additive and preferred for new clients only if both resume paths can share clear at-least-once semantics. Otherwise defer the public cursor field and keep the completion boundary internal.
  4. Add reconnect regressions for legacy id and physical cursor, including delayed preview arrival, interruption between the two physical rows, an unlinked preview negative control, and the next-message boundary.
  5. Capture redacted exact-head proof on a macOS host with Messages and Contacts permissions: one linked-preview composition, one watch event, no delayed duplicate, then reconnect once with id and once with cursor without replay or loss.
  6. Merge the focused fix without a functional-PR changelog edit, then publish it in the next imsg release.

Acceptance criteria

  • GUID-linked text and URL-preview rows produce one logical event with the URL retained.
  • Resuming from the emitted id produces no replay, duplicate, or skipped next message.
  • Resuming from cursor, if shipped, has the same observable delivery boundary.
  • History, search, stats, unread counts, and watch output retain the regression coverage from PR fix: coalesce GUID-linked URL previews #181.
  • macOS and Linux CI pass on the exact merge head.
  • Redacted exact-head live output covers delayed preview delivery and both supported reconnect tokens.

Downstream dependency

openclaw/openclaw#91243 remains open pending an imsg release that owns URL-preview coalescing. Draft openclaw/openclaw#108436 removes OpenClaw's fallback and currently names imsg 0.13.1, but that release does not contain PR #181. The downstream PR must remain draft and target the eventual release containing this fix.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Urgent regression or broken agent/channel workflow affecting real users now.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: 🦪 silver shellfishThin issue quality; more reproduction proof or environment detail is needed.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions