Skip to content

fix(native-chat): settle acknowledged messages after a paged reconnect - #28993

Merged
brennanb2025 merged 3 commits into
mainfrom
brennanb2025/nc-send-cursor-settlement
Oct 16, 2026
Merged

brennanb2025 merged 3 commits into
mainfrom
brennanb2025/nc-send-cursor-settlement

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 2 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​40 $\color{#cf222e}{\Huge{\mathbf{−}}}$​6 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​34
Prod 16 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​111 $\color{#cf222e}{\Huge{\mathbf{−}}}$​31 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​80

ELI5

A phone can keep showing an old sent message as an extra bubble after reconnecting to a long conversation. Send a message, let the agent continue while the connection is away, then reconnect after the message has moved outside the newest history page: the host confirms the send, but the phone waits forever to see its exact row. Desktop chats retain the same assumption while hidden.

Acknowledged messages now stop appearing as local echoes once the conversation read reaches the position the host confirmed. Earlier messages remain in history, and sends without an acknowledgement keep their existing delivery checks.

What Changed

Keep the journal position already supplied in a successful send reply and use the same comparison on phone and desktop. The comparison requires the same journal epoch and a read at or beyond that position. It also handles a snapshot that arrives before the send reply. Opening messages created with a chat carry their acknowledgement through the same sender.

Why

A local echo describes a send the conversation has not shown yet. Requiring its exact row couples settlement to the loaded history window; a bounded snapshot can legitimately skip that row. The host acknowledgement plus the read position prove the echo is superseded without replaying all missed history or adding an arbitrary receipt limit. This is the prerequisite for #28951.

Linked Issue

Follow-up from the native-chat performance investigation requested by @BrennanKB5.

Visual Proof

The acknowledged-send settlement case passed the Windows rendered stack run described below.

Testing

  • I manually tested these changes (remote Windows Electron)
  • Automated tests added/updated, or explained why not below

One phone flow covers an acknowledged send followed by a newest-page snapshot that excludes its row, in both reply/snapshot orders. The existing desktop sender test now checks that an unacknowledged send stays pending, an older read or another epoch cannot settle it, and a covering read retires it. Full PR CI and Mobile Checks passed at c94bf143db3. All five unit shards, static analysis/typecheck, Linux and Windows packages, and the full PR aggregate passed; Windows passed on retry after PowerShell timeouts in unchanged hook tests. Mobile passed 485 and 10,193 tests in its two runtime groups (six skips), including all 16 tests in the changed send-flow file and both reconnect orderings. No tests, builds, lint, installs, or typechecks ran on the overloaded development Mac. A fresh openclaw connection failed with Permission denied (publickey).

Review

Cross-platform and remote hosts use the journal position from the execution host; there is no new wire field or request. Older hosts already return this position. No sender retries or durable state are added.

Agent skill upstream boundary

  • Not applicable, or this change copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

Rendered QA

Windows high spec, stack commit 50b4118ccd4c8d2fab2a68e14e4d5729c41df915 (includes #28993 at c94bf143db3): private install and e2e build, one hidden Electron app, isolated profile, folder workspace, Claude stream-json stand-in, scripted Playwright over CDP. All captures assert isVisible() === false; no desktop input was used.

A send was acknowledged at position 788 while the hidden reader remained at 787. Reopening after 786 missed saved changes produced one newest-page snapshot of 200 items at position 1573; the sent row was outside that snapshot, yet the pending echo cleared. The complete final reply rendered, and loading older history showed the delivered user message. Existing viewport prefetch then loaded 200 additional items; a subsequent real mouse-wheel scroll loaded the remaining 124 (400 → 524), with position 1573 unchanged. A short gap replayed 26 saved changes (526 → 534 items) without replacing the page. Clean quit/relaunch on a fresh CDP port restored the saved tab and all 531 message records with the same SHA-256 text hash.

The original 7fcc8645fad run exposed a missing capability on the local desktop IPC reader: the same normal-reply fixture replayed 786 changes and retained 524 items; the corrected 50b4118ccd4 fixture reopened with a 200-item snapshot. The desktop capability advertisement and one subscription-boundary regression were added to #28951. This is a deterministic rendered count comparison, not a new timing benchmark. Live paired/SSH transport and phone UI were not exercised in this Windows run.

Final reply after snapshot:

Final reply preserved

Delivered message after older history loads (same corrected commit, normal-reply fixture):

Delivered user message

Older history after actual CDP wheel scrolling:

Older history loaded by wheel

Transcript after clean restart:

Transcript survives restart

@brennanb2025

brennanb2025 commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor Author

A reconnect to a long chat could leave an extra local message bubble after the host had saved the message, because the newest history page no longer contained its exact row. Desktop and mobile now retain the host’s existing acknowledgement position and remove that redundant bubble once the loaded history reaches that position in the same history version. Earlier messages remain available through history paging, and sends without an acknowledgement keep their existing checks.

One full adversarial review round, architecture challenge, desktop/mobile entry-point traces, and readiness/performance source review found no proven defect introduced by this PR. The design is retained; no production changes or additional fix round were needed. Temporary existing differences, deferred to separate follow-ups for replacing old local copies after a history reset and sharing desktop capability lists (not yet opened), are a saved message’s local copy surviving a later rewind and duplicated lists of features that desktop connections support. Intended difference from the common pattern: this client keeps the host’s existing saved position because a bounded history page can omit the acknowledged message; it adds no saved obligation or retry. A narrow hidden-chat queue scenario remains unexecuted residual risk, not a demonstrated regression.

Verified the full .github/workflows/pr.yml run and its PR checks passed aggregate on exact head c94bf143db3dd8fc693aa9afefc845c6c532a6d1: https://github.com/stablyai/orca/actions/runs/38682741482 . After taking the PR out of draft, the new full PR workflow and its PR checks passed aggregate also succeeded at that same head; GitHub reports no merge conflicts. Mobile Checks also passed separately. The Windows hidden Electron proof already attached to this PR covers settlement at combined-stack commit 50b4118ccd4, which includes this unchanged prerequisite, with all files changed by this PR identical to the current head: the pending echo cleared after an off-page 200-item snapshot, older history remained reachable, and restart preserved the recorded transcript. Its numerical claims were checked against the retained outputs and remain correctly scoped to that historical commit; no code changed, so no remeasurement was needed.

A fresh desktop comparison of this PR on its own and native mobile UI QA were not run: no QA slot was granted during the capacity wait, and this task had no owned native device. Earlier M4Air and Windows attempts stopped at preflight without launching a workload; their owned worktrees were removed. Live paired/SSH transport and independently updated native peers were not exercised. The existing Windows proof covers the unchanged settlement change; the additional desktop and native-mobile checks were not run, and those coverage limits remain disclosed. No merge was performed.

Update: real signed-in agent QA

Real signed-in Electron QA passed on exact head c94bf143db3dd8fc693aa9afefc845c6c532a6d1.

  • Claude Opus 5.5 (1M, High), hidden Electron/CDP, real in-place login; automatic chat naming disabled in Settings UI.
  • Real composer send while the chat tab was hidden; acknowledged row sequence 13 fell off the newest 200-item page (newest 46–476, older 3–45, 234 items total, 225 distinct Read calls). Reopen cleared the Sending bubble; older scrolling showed the original prompt and stable ordering.
  • After owner-controlled restart, the same saved chat rendered the completed REAL_QA_COMPLETE reply with no Sending bubble. Full projected transcript SHA-256 remained d712921a9a9b04bd83fd749634ea9ef8f45f9cd0fbe61bd07aff4c9e7bea61ac before and after restart.

Newest page after reopen
Older history after scroll
Saved chat after restart

Hook hashes were unchanged: Claude settings 5898f6da61f53071d9536f5c9e9033c4bb3a4f23a40cbcd6153bc0b1a5f46fcc; Codex hooks edb2d1cab54568e86a32aa813939d8a8892f1184a0d13bddbd08e9059a723eee.

@coderabbitai

coderabbitai Bot commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: a80d6abc-6c12-4fdd-9eaf-8cf3863d4ff7
📥 Commits

Reviewing files that changed from the base of the PR and between 209ef94 and c94bf14.

📒 Files selected for processing: 18
  • mobile/src/session/mobile-structured-agent-session-rpc.ts
  • mobile/src/session/mobile-structured-agent-session-send.ts
  • mobile/src/session/use-mobile-structured-agent-session.ts
  • mobile/src/session/use-mobile-structured-send-with-outcome.ts
  • mobile/src/session/use-mobile-structured-sends.test.tsx
  • mobile/src/session/use-mobile-structured-sends.ts
  • src/renderer/src/components/native-chat/structured-agent-session-message-sender.test.ts
  • src/renderer/src/components/native-chat/structured-agent-session-message-sender.ts
  • src/renderer/src/components/native-chat/structured-agent-session-pending-sends.ts
  • src/renderer/src/components/native-chat/structured-agent-session-send-attempt.ts
  • src/renderer/src/components/native-chat/structured-agent-session-send-runtime.ts
  • src/renderer/src/components/native-chat/use-structured-agent-session-sends.ts
  • src/renderer/src/components/native-chat/use-structured-agent-session.ts
  • src/renderer/src/lib/structured-agent-session-launch-create-call.ts
  • src/renderer/src/lib/structured-agent-session-launch-prompt.ts
  • src/renderer/src/lib/structured-agent-session-launch-recovery.ts
  • src/shared/structured-agent-session-message-projection.ts
  • src/shared/structured-agent-session-send-settlement.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 7 remain after this review.

📝 Walkthrough

Accepted send results now carry journal cursors through mobile and renderer flows. Pending sends retain those cursors, and journal reconciliation can settle a recorded send when a read cursor covers its acknowledgement, even if the message is absent from the returned cards. Tests cover cursor matching and snapshot/reply ordering.

Priority: ➖ Normal

Merge Risk: ⚪ Minimal · up to c94bf

This change retires acknowledged send echoes once a journal read covers the acknowledgement, even if the message row is off-page. No merge-blocking risk is evident from the supplied context.

Pre-merge checks: Passed 3 · Failed 2

Failed Failed checks: 2 warnings

Check name Status Explanation Resolution
Description check Warning The description is detailed and covers the user impact, implementation, rationale, testing, visual proof, and checklist. However, the required Linked Issue section does not include an actual issue lin… Add the actual issue reference, such as Fixes #28951, in the Linked Issue section. Keep the existing testing and visual-proof details.
Docstring Coverage Warning Docstring coverage is 41.18% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 17 functions across 18 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 3 passed
Check name Status Explanation
Title check Passed The title clearly identifies the main change: settling acknowledged native-chat messages after a paged reconnect.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description is detailed and covers the user impact, implementation, rationale, testing, visual proof, and checklist. However, the required Linked Issue section does not include an actual issue link or a completed Fixes reference.

  • Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@brennanb2025
brennanb2025 merged commit d6f9df9 into main Oct 16, 2026
77 of 79 checks passed
@brennanb2025
brennanb2025 deleted the brennanb2025/nc-send-cursor-settlement branch October 16, 2026 01:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant