Skip to content

fix(ios): persist queued Watch replies#100372

Merged
steipete merged 2 commits into
mainfrom
codex/pr-100031-replacement
Jul 5, 2026
Merged

fix(ios): persist queued Watch replies#100372
steipete merged 2 commits into
mainfrom
codex/pr-100031-replacement

Conversation

@steipete

@steipete steipete commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Apple Watch quick replies were accepted in memory and could be lost when the iOS app was offline, suspended, or terminated before Gateway delivery. Delayed WatchConnectivity fallbacks could also duplicate delivery or route a reply after the active Gateway changed.

This supersedes #100031 after GitHub auto-closed the contributor branch during a maintainer ancestry repair. The implementation and contributor attribution are preserved here so the reviewed fix can land cleanly.

Why This Change Was Made

  • Reuse the existing durable, gateway-scoped Watch message outbox instead of maintaining a second reply queue.
  • Persist accepted messages before awaiting delivery and use chat.send idempotency keys.
  • Carry source-Gateway identity through Watch notifications and persist bounded prompt routes for released Watch builds.
  • Persist bounded delivery tombstones to deduplicate delayed fallbacks across process restarts.
  • Serialize flushes, prioritize replies, revalidate Gateway identity before every send, and retain bounded transient retries.
  • Preserve current Watch chat/voice behavior while quick replies finish without waiting for spoken completion.

User Impact

Watch quick replies survive iPhone process loss and reconnects, avoid duplicate sends, and never guess across Gateways. Existing watch.chat.command.queue.v1 data remains decodable.

Evidence

  • xcrun swiftc -parse on all changed iOS/watchOS Swift files
  • swiftformat --lint --config config/swiftformat on changed app sources
  • node --import tsx scripts/native-app-i18n.ts check
  • git diff --check
  • Fresh Codex autoreview after fixing the pre-upgrade prompt finding: no accepted/actionable findings
  • Exact-head GitHub CI run 28746617125: passed, including ios-build, macos-swift, macos-node, native i18n, and Node shards
  • Exact-head Workflow Sanity 28746617099 and iOS Periphery 28746617098: passed
  • Repo-native OPENCLAW_TESTBOX=1 scripts/pr prepare-run 100372: passed exact-head hosted gates

Known gap: no physical Apple Watch round-trip was available. Native build/test lanes cover the changed Apple surfaces.

Attribution

Original implementation by @NianJiuZst in #100031; replacement commit retains Co-authored-by credit.

Route Apple Watch quick replies through the durable, gateway-scoped Watch message outbox with restart-safe routing and deduplication.

Co-authored-by: NianJiuZst <[email protected]>
@openclaw-barnacle openclaw-barnacle Bot added app: ios App: ios size: L maintainer Maintainer-authored PR labels Jul 5, 2026
@clawsweeper

clawsweeper Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 5, 2026, 12:10 PM ET / 16:10 UTC.

Summary
The PR routes iOS Watch quick replies through the durable gateway-scoped Watch message outbox, adds gateway routing metadata, retry/dedupe handling, Watch payload plumbing, iOS tests, i18n baseline updates, and a changelog line.

PR surface: Docs +1, Other +436. Total +437 across 11 files.

Reproducibility: yes. from source inspection. Current main accepts Watch quick replies into process-local arrays, so queued replies and dedupe state can be lost across suspension or termination; I did not run a physical Watch reproduction.

Review metrics: 1 noteworthy metric.

  • Persistent Watch state surfaces: 1 existing key reused, 1 metadata key added. The change affects restart and upgrade behavior, so maintainers should review stored Watch queue compatibility before merge.

Root-cause cluster
Relationship: canonical
Canonical: #100372
Summary: This PR is the active replacement for the closed unmerged predecessor that carried the same Watch reply persistence work.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦪 silver shellfish
Proof: 🦪 silver shellfish
Patch quality: 🐚 platinum hermit
Result: blocked until real behavior proof is added.

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

Rank-up moves:

  • [P1] Add redacted real Watch or WatchConnectivity proof showing queued replies survive reconnect or restart without duplicate or cross-gateway delivery.
  • Remove the direct CHANGELOG.md entry and keep release-note context in the PR body or squash message.
  • After adding proof, update the PR body so ClawSweeper can re-review the current head.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR has parse/lint/i18n/autoreview evidence but no real Apple Watch or WatchConnectivity after-fix proof, and the body explicitly calls out that device gap. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Mantis proof suggestion
A visible or diagnostic iOS Watch/WatchConnectivity run would materially prove the user-visible delivery behavior that CI cannot show. A maintainer can ask Mantis to capture proof by posting this exact PR comment:

@openclaw-mantis visual task: verify iOS Apple Watch quick replies survive reconnect/restart and do not duplicate or switch gateways, with private details redacted.

Risk before merge

  • [P1] No real Apple Watch or WatchConnectivity after-fix run is linked, so CI and source review do not prove the actual device delivery path.
  • [P1] The diff changes durable Watch outbox storage, delivered-message tombstones, retry behavior, and source-gateway binding, so a regression could lose, duplicate, or misroute Watch-originated agent turns.
  • [P1] The PR still edits release-owned CHANGELOG.md directly, which can duplicate or stale the generated release notes if merged as a normal fix PR.

Maintainer options:

  1. Prove and land the gateway-scoped outbox (recommended)
    Remove the direct changelog edit, let exact-head checks finish, and add real Watch or WatchConnectivity proof before merge.
  2. Override the device-proof gap
    A maintainer may intentionally accept CI/source proof only, but should make that override explicit because the changed behavior is device-delivery sensitive.
  3. Pause for the broader iOS outbox
    If feat(ios): durable offline command outbox for chat sends #100331 is the intended canonical queue, pause or supersede this PR after preserving the Watch-specific fix details.

Next step before merge

  • [P1] Manual maintainer handling is needed for proof sufficiency or override on a maintainer-labeled Watch message-delivery PR; automation cannot supply the missing device proof.

Maintainer decision needed

  • Question: Should this PR wait for real Apple Watch or diagnostic WatchConnectivity proof before merge, or may maintainers explicitly override that proof gap for this hardware-limited fix?
  • Rationale: The changed path is user-visible message delivery plus persisted session/routing state, while the PR body says no physical Apple Watch round-trip was available.
  • Likely owner: steipete — steipete adopted the replacement branch and has the clearest recent iOS/watch ownership trail for this exact path.
  • Options:
    • Require real Watch proof (recommended): Ask for redacted device logs, a recording, terminal output, or another linked artifact showing queued quick replies surviving reconnect or restart without duplicate or cross-gateway delivery.
    • Accept a proof override: A maintainer can explicitly accept the missing device proof after reviewing the source, regression tests, and exact-head CI evidence.
    • Fold into broader outbox work: Pause this PR if maintainers want the Watch reply persistence to land through the broader offline outbox stack in feat(ios): durable offline command outbox for chat sends #100331.

Security
Cleared: No dependency, workflow, credential, or supply-chain regression was found; the gateway-binding changes remain merge-risk sensitive but are not a concrete security defect.

Review findings

  • [P3] Remove the direct changelog entry — CHANGELOG.md:30
Review details

Best possible solution:

Keep the gateway-scoped durable Watch outbox approach, remove the direct changelog edit, finish exact-head validation, and require real Watch/WatchConnectivity proof or an explicit maintainer proof override before merge.

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

Yes, from source inspection. Current main accepts Watch quick replies into process-local arrays, so queued replies and dedupe state can be lost across suspension or termination; I did not run a physical Watch reproduction.

Is this the best way to solve the issue?

Mostly yes. Reusing one durable gateway-scoped Watch outbox is the right fix boundary, but the merge artifact still needs real behavior proof or an explicit override plus changelog cleanup.

Full review comments:

  • [P3] Remove the direct changelog entry — CHANGELOG.md:30
    OpenClaw release generation owns CHANGELOG.md for normal PRs, and this PR already carries the release-note context in its body. Keeping this line can duplicate or stale the generated notes, so remove it from the PR branch.
    Confidence: 0.88

Overall correctness: patch is correct
Overall confidence: 0.82

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 286d0b9fb340.

Label changes

Label changes:

  • add P2: This is a normal-priority iOS/watch message-loss fix with limited platform scope and no proven emergency impact.
  • add merge-risk: 🚨 message-delivery: The diff changes how Watch quick replies are queued, retried, deduped, delivered, and discarded.
  • add merge-risk: 🚨 session-state: The diff persists Watch outbox metadata, prompt routes, and delivery tombstones across process restarts.
  • add merge-risk: 🚨 security-boundary: The diff changes source-gateway binding so stale Watch actions cannot be sent through a newly selected gateway.
  • add rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🐚 platinum hermit.
  • add status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR has parse/lint/i18n/autoreview evidence but no real Apple Watch or WatchConnectivity after-fix proof, and the body explicitly calls out that device gap. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Label justifications:

  • P2: This is a normal-priority iOS/watch message-loss fix with limited platform scope and no proven emergency impact.
  • merge-risk: 🚨 message-delivery: The diff changes how Watch quick replies are queued, retried, deduped, delivered, and discarded.
  • merge-risk: 🚨 session-state: The diff persists Watch outbox metadata, prompt routes, and delivery tombstones across process restarts.
  • merge-risk: 🚨 security-boundary: The diff changes source-gateway binding so stale Watch actions cannot be sent through a newly selected gateway.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🐚 platinum hermit.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR has parse/lint/i18n/autoreview evidence but no real Apple Watch or WatchConnectivity after-fix proof, and the body explicitly calls out that device gap. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Docs +1, Other +436. Total +437 across 11 files.

View PR surface stats
Area Files Added Removed Net
Source 0 0 0 0
Tests 0 0 0 0
Docs 1 1 0 +1
Config 0 0 0 0
Generated 0 0 0 0
Other 10 712 276 +436
Total 11 713 276 +437

What I checked:

  • Repository policy applied: Root AGENTS.md marks CHANGELOG.md as release-only for normal PRs, and scoped iOS AGENTS.md was also read for app-specific review context. (AGENTS.md:238, 286d0b9fb340)
  • Current main source behavior: Current main stores accepted Watch quick replies only in process memory, so queued replies and dedupe state disappear if the iOS process exits before delivery. (apps/ios/Sources/Model/WatchReplyCoordinator.swift:12, 286d0b9fb340)
  • PR persistence implementation: The PR replaces separate reply/chat coordinators with WatchMessageOutbox, keeps the shipped queue key, adds metadata, and persists a queued message before returning either forward or queue. (apps/ios/Sources/Model/WatchReplyCoordinator.swift:13, ff74edbb40b5)
  • PR gateway routing behavior: The PR resolves Watch reply source gateway identity from payload metadata, persisted prompt routes, or the explicit pre-upgrade fallback, then drops stale or unresolved targets before queueing/sending. (apps/ios/Sources/Model/NodeAppModel.swift:3288, ff74edbb40b5)
  • Regression coverage: The PR adds tests for offline reply queueing, restore after restart, persisted tombstones/routes, stale gateway drops, idempotent delivery, and legacy prompt binding. (apps/ios/Tests/NodeAppModelInvokeTests.swift:1977, ff74edbb40b5)
  • Real behavior proof gap: The PR body lists parse, lint, i18n, diff, and autoreview evidence, but explicitly notes no physical Apple Watch round-trip was available. (ff74edbb40b5)

Likely related people:

  • steipete: Peter Steinberger authored the current replacement commits and recent merged Apple Watch voice-turn work, and history shows him extracting the Watch reply coordinator now being refactored. (role: recent iOS/watch contributor and PR adopter; confidence: high; commits: ff74edbb40b5, 245092dc3ae1, f399a818ef68; files: apps/ios/Sources/Model/NodeAppModel.swift, apps/ios/Sources/Model/WatchReplyCoordinator.swift, apps/ios/Tests/NodeAppModelInvokeTests.swift)
  • mbelinky: GitHub PR history shows Mariano authored the Apple Watch companion MVP and mirrored notification quick-reply bridge that this PR hardens. (role: introduced adjacent Watch messaging foundations; confidence: medium; commits: 57083e4220e3, 738b011624c7, f52476f18c37; files: apps/ios/Sources/Services/WatchMessagingPayloadCodec.swift, apps/ios/Sources/OpenClawApp.swift, apps/ios/WatchApp/Sources/WatchConnectivityReceiver.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.

Bind shipped notification prompts without routing metadata to the current Gateway once, while keeping explicit and persisted Gateway owners fail-closed.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 725615af2b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CHANGELOG.md
- **Model aliases:** resolve provider-qualified aliases during session and chat-command model switches without collisions when providers share a display alias. (#100209) Thanks @sahilsatralkar.
- **TUI new-session hooks:** create `/new` sessions through the shared Gateway lifecycle so command and session hooks receive the completed parent transcript in both Gateway and embedded modes, while preventing rollover during an active turn. (#100241, #49918) Thanks @BingqingLyu.
- **TUI abort diagnostics:** show sanitized tool argument-validation summaries for aborted runs in both Gateway and local TUI modes without exposing raw model arguments. (#91002) Thanks @wsyjh8.
- **iOS Watch replies:** persist queued quick replies in the gateway-scoped chat outbox and submit them through idempotent chat delivery, preventing losses, duplicates, and cross-gateway sends after reconnects. (#100031) Thanks @NianJiuZst.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove the direct changelog entry

For normal fixes, the root AGENTS.md says CHANGELOG.md is release-only and generated from merged PRs/direct commits, so adding this line directly can leave the next release-generation pass with duplicate or stale release notes. Unless this commit is the release-generation commit, keep this context in the commit/PR body and let the changelog generator create the entry.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. labels Jul 5, 2026
@steipete

steipete commented Jul 5, 2026

Copy link
Copy Markdown
Contributor Author

Land-ready review complete for ff74edbb40b5ffccd223b9563045d3a07adfe67f.

What changed:

  • Replaced the separate quick-reply queue with the existing durable, gateway-scoped Watch message outbox.
  • Persist before delivery; use chat.send idempotency keys; retain bounded retries, delivery tombstones, and prompt-to-gateway routes across restarts.
  • Carry source Gateway IDs through WatchConnectivity and mirrored iOS actions; reject stale explicit routes.
  • Preserve released Watch compatibility through recorded prompt routes and bind pre-upgrade prompts without routing metadata once to the current Gateway.
  • Preserve the shipped watch.chat.command.queue.v1 data shape and contributor co-authorship from fix: persist queued iOS watch replies #100031.

Proof:

  • xcrun swiftc -parse on all changed iOS/watchOS Swift files
  • swiftformat --lint --config config/swiftformat on changed app sources
  • node --import tsx scripts/native-app-i18n.ts check
  • git diff --check
  • Fresh Codex autoreview after the upgrade-path fix: no accepted/actionable findings
  • Exact-head GitHub CI run 28746617125: passed, including ios-build, macos-swift, macos-node, native i18n, and Node shards
  • Exact-head Workflow Sanity 28746617099 and iOS Periphery 28746617098: passed
  • Repo-native OPENCLAW_TESTBOX=1 scripts/pr prepare-run 100372: passed exact-head hosted gates; review artifacts validate READY FOR /prepare-pr with zero findings

Known gap: no physical Apple Watch round-trip was available. Native build and test lanes cover the changed Apple surfaces.

@steipete
steipete merged commit 70f2bef into main Jul 5, 2026
125 of 134 checks passed
@steipete

steipete commented Jul 5, 2026

Copy link
Copy Markdown
Contributor Author

Merged via squash.

@steipete
steipete deleted the codex/pr-100031-replacement branch July 5, 2026 16:14
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 6, 2026
* fix(ios): persist queued watch replies

Route Apple Watch quick replies through the durable, gateway-scoped Watch message outbox with restart-safe routing and deduplication.

Co-authored-by: NianJiuZst <[email protected]>

* fix(ios): preserve pre-upgrade Watch replies

Bind shipped notification prompts without routing metadata to the current Gateway once, while keeping explicit and persisted Gateway owners fail-closed.

---------

Co-authored-by: NianJiuZst <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: ios App: ios maintainer Maintainer-authored PR merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P2 Normal backlog priority with limited blast radius. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. size: L status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant