Skip to content

fix(native-chat): order pending user prompts chronologically and tolerate cross-host clock skew (#23851) - #24207

Open
LesleyMurfin wants to merge 2 commits into
stablyai:mainfrom
LesleyMurfin:ai/bug-chat-ui-showing-out-of-sequence-messages
Open

LesleyMurfin wants to merge 2 commits into
stablyai:mainfrom
LesleyMurfin:ai/bug-chat-ui-showing-out-of-sequence-messages

Conversation

@LesleyMurfin

@LesleyMurfin LesleyMurfin commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 3 +100 -13 +87
Prod 4 +115 -35 +80

ELI5

When you submit a message in the chat UI, the user prompt is shown immediately as a pending prompt while the assistant starts thinking and streaming its reply. Previously, the pending prompt was artificially assigned a lower sorting rank ("Rank 2") than assistant responses ("Rank 0") and streaming previews ("Rank 1"). This caused newly submitted prompts to jump below subsequent assistant messages or streaming text instead of staying above the reply they triggered. In addition, follow-up prompts queued while the agent was busy needed to cleanly sort below active turns without cross-clock comparisons between host and client clocks. This fix aligns pending prompts chronologically, tracks queued follow-ups against the host working epoch in a single clock domain, and handles clock skew cleanly.

What Changed

What broke, as a user sees it:
Occasionally, when sending a prompt or pasting instructions into the chat UI, the user's prompt rendered after the assistant's reply (or streaming preview bubble) rather than before it (#23851). In multi-turn chats or rapid exchanges, the prompt-response causality appeared inverted on screen. Furthermore, launch prompts could become stranded indefinitely at the bottom of the transcript if client and server clocks differed.

Why:

  1. In , assigned pending user prompts ( and ) to Rank 2, sorting them strictly after authoritative transcript messages (Rank 0, including assistant replies) and active streaming previews (Rank 1). When a prompt was submitted, subsequent assistant responses rendered above the prompt rather than below it.
  2. In , was concatenated before , causing the active streaming bubble to precede optimistic user echoes during generation.
  3. In , clock skew between the client renderer and remote transcript host was unhandled in and , stranding launch prompts at the bottom of the list indefinitely.
  4. When follow-up prompts are queued mid-turn, determining whether a pending prompt is actively queued behind the ongoing turn requires avoiding cross-clock subtractions between renderer and host . Comparing like clocks (tracking on the pending entry matched against live ) ensures the triggering prompt is never falsely classified as queued even if the remote host clock lags behind the client.

After this PR:

  • Demoted so pending user prompts share Rank 0 and sort by their chronological timestamp unless explicitly queued behind an active turn (Rank 2).
  • Streaming assistant preview bubble () remains Rank 1, sorting directly after the prompt that triggered it.
  • Corrected bubble concatenation in so optimistic echoes precede the streaming preview.
  • Added cross-host clock skew tolerance () to launch prompt matching and client-side boundaries, while preserving exact strict ordering on server-side transcript boundaries ().
  • Evaluated dynamically using against in the same clock domain, completely avoiding cross-clock math.

Why

User prompts naturally precede the model's response in conversation flow. Assigning pending prompts to an artificial Rank 2 was intended to ensure pending items didn't displace finalized history, but it had the unintended consequence of pushing user prompts below active streaming previews and subsequent transcript arrivals. Unifying pending user prompts into Rank 0 sorted by chronological timestamp preserves conversational causality without special-case heuristics. Tracking queued follow-ups within the host's clock domain ensures robust sorting across local and remote/SSH setups.

Linked Issue

Fixes #23851

Visual Proof

Visual sequence flow comparison:

Testing

  • Automated tests in:

  • Specific unit test verifying that when host clock lags (), a prompt triggering the turn is NOT flagged queued and sorts before the streaming preview.

  • Typecheck (Scope: all 2 workspace projects
    ✓ Lockfile passes supply-chain policies (verified 7h ago)
    Lockfile is up to date, resolution step is skipped
    Already up to date
    native/windows-registry install$ node-gyp rebuild
    native/windows-registry install: gyp info it worked if it ends with ok
    native/windows-registry install: gyp info using node-gyp@12.3.0
    native/windows-registry install: gyp info using node@24.19.0 | linux | x64
    native/windows-registry install: gyp info find Python using Python version 3.12.3 found at "/usr/bin/python3"
    native/windows-registry install:
    native/windows-registry install: gyp info spawn /usr/bin/python3
    native/windows-registry install: gyp info spawn args [
    native/windows-registry install: gyp info spawn args '/home/lesley/.cache/node/corepack/v1/pnpm/12.0.0/dist/node_modules/node-gyp/gyp/gyp_main.py',
    native/windows-registry install: gyp info spawn args 'binding.gyp',
    native/windows-registry install: gyp info spawn args '-f',
    native/windows-registry install: gyp info spawn args 'make',
    native/windows-registry install: gyp info spawn args '-I',
    native/windows-registry install: gyp info spawn args '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/native/windows-registry/build/config.gypi',
    native/windows-registry install: gyp info spawn args '-I',
    native/windows-registry install: gyp info spawn args '/home/lesley/.cache/node/corepack/v1/pnpm/12.0.0/dist/node_modules/node-gyp/addon.gypi',
    native/windows-registry install: gyp info spawn args '-I',
    native/windows-registry install: gyp info spawn args '/home/lesley/.cache/node-gyp/24.19.0/include/node/common.gypi',
    native/windows-registry install: gyp info spawn args '-Dlibrary=shared_library',
    native/windows-registry install: gyp info spawn args '-Dvisibility=default',
    native/windows-registry install: gyp info spawn args '-Dnode_root_dir=/home/lesley/.cache/node-gyp/24.19.0',
    native/windows-registry install: gyp info spawn args '-Dnode_gyp_dir=/home/lesley/.cache/node/corepack/v1/pnpm/12.0.0/dist/node_modules/node-gyp',
    native/windows-registry install: gyp info spawn args '-Dnode_lib_file=/home/lesley/.cache/node-gyp/24.19.0/<(target_arch)/node.lib',
    native/windows-registry install: gyp info spawn args '-Dmodule_root_dir=/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/native/windows-registry',
    native/windows-registry install: gyp info spawn args '-Dnode_engine=v8',
    native/windows-registry install: gyp info spawn args '--depth=.',
    native/windows-registry install: gyp info spawn args '--no-parallel',
    native/windows-registry install: gyp info spawn args '--generator-output',
    native/windows-registry install: gyp info spawn args 'build',
    native/windows-registry install: gyp info spawn args '-Goutput_dir=.'
    native/windows-registry install: gyp info spawn args ]
    native/windows-registry install: gyp info spawn make
    native/windows-registry install: gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
    native/windows-registry install: make: Entering directory '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/native/windows-registry/build'
    native/windows-registry install: TOUCH Release/obj.target/orca_windows_registry.stamp
    native/windows-registry install: make: Leaving directory '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/native/windows-registry/build'
    native/windows-registry install: gyp info ok
    native/windows-registry install: Done
    . postinstall$ node config/scripts/rebuild-native-deps.mjs
    . postinstall: [rebuild] Skipping optional Electron rebuild modules: cpu-features
    . postinstall: [rebuild] Native modules already load in Electron; skipping rebuild.
    . postinstall: Done
    . prepare$ husky
    . prepare: node:fs:3177
    . prepare: binding.copyFile(
    . prepare: ^
    . prepare:
    . prepare: Error: EACCES: permission denied, copyfile '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/node_modules/.pnpm/husky@9.1.7/node_modules/husky/husky' -> '.husky//h'
    . prepare: at Object.copyFileSync (node:fs:3177:11)
    . prepare: at default (file:///data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/node_modules/.pnpm/husky@9.1.7/node_modules/husky/index.js:21:4)
    . prepare: at file:///data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/node_modules/.pnpm/husky@9.1.7/node_modules/husky/bin.js:26:16
    . prepare: at ModuleJob.run (node:internal/modules/esm/module_job:439:25)
    . prepare: at async node:internal/modules/esm/loader:643:26
    . prepare: at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5) {
    . prepare: errno: -13,
    . prepare: code: 'EACCES',
    . prepare: syscall: 'copyfile',
    . prepare: path: '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/node_modules/.pnpm/husky@9.1.7/node_modules/husky/husky',
    . prepare: dest: '.husky/
    /h'
    . prepare: }
    . prepare:
    . prepare: Node.js v24.19.0
    . prepare: Failed) and full vitest suite in all passing (220/220 test files, 2284/2284 tests).

  • I manually tested these changes locally

  • Automated tests added/updated, or explained why not below

AI Disclosure

Prepared with Claude Code. Reviewed and verified by Lesley Murfin.

Review

  • Backwards compatibility: No data schema or RPC changes. Affects only client renderer message assembly and grouping.
  • Clock skew: Slack () is isolated to client-sent timestamps; server-side transcript boundaries remain strictly ordered; queued state comparison stays in host clock domain.
  • Performance: Message assembly sorting logic runs (N \log N)$ over visible messages as before, with reduced branching in rank comparison.

Agent skill upstream boundary

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

Notes

  • Cross-platform verified on Linux and macOS environments.

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 with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • Scope: all 2 workspace projects
    ✓ Lockfile passes supply-chain policies (verified 7h ago)
    Lockfile is up to date, resolution step is skipped
    Already up to date
    native/windows-registry install$ node-gyp rebuild
    native/windows-registry install: gyp info it worked if it ends with ok
    native/windows-registry install: gyp info using node-gyp@12.3.0
    native/windows-registry install: gyp info using node@24.19.0 | linux | x64
    native/windows-registry install: gyp info find Python using Python version 3.12.3 found at "/usr/bin/python3"
    native/windows-registry install:
    native/windows-registry install: gyp info spawn /usr/bin/python3
    native/windows-registry install: gyp info spawn args [
    native/windows-registry install: gyp info spawn args '/home/lesley/.cache/node/corepack/v1/pnpm/12.0.0/dist/node_modules/node-gyp/gyp/gyp_main.py',
    native/windows-registry install: gyp info spawn args 'binding.gyp',
    native/windows-registry install: gyp info spawn args '-f',
    native/windows-registry install: gyp info spawn args 'make',
    native/windows-registry install: gyp info spawn args '-I',
    native/windows-registry install: gyp info spawn args '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/native/windows-registry/build/config.gypi',
    native/windows-registry install: gyp info spawn args '-I',
    native/windows-registry install: gyp info spawn args '/home/lesley/.cache/node/corepack/v1/pnpm/12.0.0/dist/node_modules/node-gyp/addon.gypi',
    native/windows-registry install: gyp info spawn args '-I',
    native/windows-registry install: gyp info spawn args '/home/lesley/.cache/node-gyp/24.19.0/include/node/common.gypi',
    native/windows-registry install: gyp info spawn args '-Dlibrary=shared_library',
    native/windows-registry install: gyp info spawn args '-Dvisibility=default',
    native/windows-registry install: gyp info spawn args '-Dnode_root_dir=/home/lesley/.cache/node-gyp/24.19.0',
    native/windows-registry install: gyp info spawn args '-Dnode_gyp_dir=/home/lesley/.cache/node/corepack/v1/pnpm/12.0.0/dist/node_modules/node-gyp',
    native/windows-registry install: gyp info spawn args '-Dnode_lib_file=/home/lesley/.cache/node-gyp/24.19.0/<(target_arch)/node.lib',
    native/windows-registry install: gyp info spawn args '-Dmodule_root_dir=/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/native/windows-registry',
    native/windows-registry install: gyp info spawn args '-Dnode_engine=v8',
    native/windows-registry install: gyp info spawn args '--depth=.',
    native/windows-registry install: gyp info spawn args '--no-parallel',
    native/windows-registry install: gyp info spawn args '--generator-output',
    native/windows-registry install: gyp info spawn args 'build',
    native/windows-registry install: gyp info spawn args '-Goutput_dir=.'
    native/windows-registry install: gyp info spawn args ]
    native/windows-registry install: gyp info spawn make
    native/windows-registry install: gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
    native/windows-registry install: make: Entering directory '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/native/windows-registry/build'
    native/windows-registry install: TOUCH Release/obj.target/orca_windows_registry.stamp
    native/windows-registry install: make: Leaving directory '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/native/windows-registry/build'
    native/windows-registry install: gyp info ok
    native/windows-registry install: Done
    . postinstall$ node config/scripts/rebuild-native-deps.mjs
    . postinstall: [rebuild] Skipping optional Electron rebuild modules: cpu-features
    . postinstall: [rebuild] Native modules already load in Electron; skipping rebuild.
    . postinstall: Done
    . prepare$ husky
    . prepare: node:fs:3177
    . prepare: binding.copyFile(
    . prepare: ^
    . prepare:
    . prepare: Error: EACCES: permission denied, copyfile '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/node_modules/.pnpm/husky@9.1.7/node_modules/husky/husky' -> '.husky//h'
    . prepare: at Object.copyFileSync (node:fs:3177:11)
    . prepare: at default (file:///data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/node_modules/.pnpm/husky@9.1.7/node_modules/husky/index.js:21:4)
    . prepare: at file:///data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/node_modules/.pnpm/husky@9.1.7/node_modules/husky/bin.js:26:16
    . prepare: at ModuleJob.run (node:internal/modules/esm/module_job:439:25)
    . prepare: at async node:internal/modules/esm/loader:643:26
    . prepare: at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5) {
    . prepare: errno: -13,
    . prepare: code: 'EACCES',
    . prepare: syscall: 'copyfile',
    . prepare: path: '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/node_modules/.pnpm/husky@9.1.7/node_modules/husky/husky',
    . prepare: dest: '.husky/
    /h'
    . prepare: }
    . prepare:
    . prepare: Node.js v24.19.0
    . prepare: Failed, Scope: all 2 workspace projects
    ✓ Lockfile passes supply-chain policies (verified 7h ago)
    Lockfile is up to date, resolution step is skipped
    Already up to date
    native/windows-registry install$ node-gyp rebuild
    native/windows-registry install: gyp info it worked if it ends with ok
    native/windows-registry install: gyp info using node-gyp@12.3.0
    native/windows-registry install: gyp info using node@24.19.0 | linux | x64
    native/windows-registry install: gyp info find Python using Python version 3.12.3 found at "/usr/bin/python3"
    native/windows-registry install:
    native/windows-registry install: gyp info spawn /usr/bin/python3
    native/windows-registry install: gyp info spawn args [
    native/windows-registry install: gyp info spawn args '/home/lesley/.cache/node/corepack/v1/pnpm/12.0.0/dist/node_modules/node-gyp/gyp/gyp_main.py',
    native/windows-registry install: gyp info spawn args 'binding.gyp',
    native/windows-registry install: gyp info spawn args '-f',
    native/windows-registry install: gyp info spawn args 'make',
    native/windows-registry install: gyp info spawn args '-I',
    native/windows-registry install: gyp info spawn args '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/native/windows-registry/build/config.gypi',
    native/windows-registry install: gyp info spawn args '-I',
    native/windows-registry install: gyp info spawn args '/home/lesley/.cache/node/corepack/v1/pnpm/12.0.0/dist/node_modules/node-gyp/addon.gypi',
    native/windows-registry install: gyp info spawn args '-I',
    native/windows-registry install: gyp info spawn args '/home/lesley/.cache/node-gyp/24.19.0/include/node/common.gypi',
    native/windows-registry install: gyp info spawn args '-Dlibrary=shared_library',
    native/windows-registry install: gyp info spawn args '-Dvisibility=default',
    native/windows-registry install: gyp info spawn args '-Dnode_root_dir=/home/lesley/.cache/node-gyp/24.19.0',
    native/windows-registry install: gyp info spawn args '-Dnode_gyp_dir=/home/lesley/.cache/node/corepack/v1/pnpm/12.0.0/dist/node_modules/node-gyp',
    native/windows-registry install: gyp info spawn args '-Dnode_lib_file=/home/lesley/.cache/node-gyp/24.19.0/<(target_arch)/node.lib',
    native/windows-registry install: gyp info spawn args '-Dmodule_root_dir=/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/native/windows-registry',
    native/windows-registry install: gyp info spawn args '-Dnode_engine=v8',
    native/windows-registry install: gyp info spawn args '--depth=.',
    native/windows-registry install: gyp info spawn args '--no-parallel',
    native/windows-registry install: gyp info spawn args '--generator-output',
    native/windows-registry install: gyp info spawn args 'build',
    native/windows-registry install: gyp info spawn args '-Goutput_dir=.'
    native/windows-registry install: gyp info spawn args ]
    native/windows-registry install: gyp info spawn make
    native/windows-registry install: gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
    native/windows-registry install: make: Entering directory '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/native/windows-registry/build'
    native/windows-registry install: TOUCH Release/obj.target/orca_windows_registry.stamp
    native/windows-registry install: make: Leaving directory '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/native/windows-registry/build'
    native/windows-registry install: gyp info ok
    native/windows-registry install: Done
    . postinstall$ node config/scripts/rebuild-native-deps.mjs
    . postinstall: [rebuild] Skipping optional Electron rebuild modules: cpu-features
    . postinstall: [rebuild] Native modules already load in Electron; skipping rebuild.
    . postinstall: Done
    . prepare$ husky
    . prepare: node:fs:3177
    . prepare: binding.copyFile(
    . prepare: ^
    . prepare:
    . prepare: Error: EACCES: permission denied, copyfile '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/node_modules/.pnpm/husky@9.1.7/node_modules/husky/husky' -> '.husky//h'
    . prepare: at Object.copyFileSync (node:fs:3177:11)
    . prepare: at default (file:///data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/node_modules/.pnpm/husky@9.1.7/node_modules/husky/index.js:21:4)
    . prepare: at file:///data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/node_modules/.pnpm/husky@9.1.7/node_modules/husky/bin.js:26:16
    . prepare: at ModuleJob.run (node:internal/modules/esm/module_job:439:25)
    . prepare: at async node:internal/modules/esm/loader:643:26
    . prepare: at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5) {
    . prepare: errno: -13,
    . prepare: code: 'EACCES',
    . prepare: syscall: 'copyfile',
    . prepare: path: '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/node_modules/.pnpm/husky@9.1.7/node_modules/husky/husky',
    . prepare: dest: '.husky/
    /h'
    . prepare: }
    . prepare:
    . prepare: Node.js v24.19.0
    . prepare: Failed, Scope: all 2 workspace projects
    ✓ Lockfile passes supply-chain policies (verified 7h ago)
    Lockfile is up to date, resolution step is skipped
    Already up to date
    native/windows-registry install$ node-gyp rebuild
    native/windows-registry install: gyp info it worked if it ends with ok
    native/windows-registry install: gyp info using node-gyp@12.3.0
    native/windows-registry install: gyp info using node@24.19.0 | linux | x64
    native/windows-registry install: gyp info find Python using Python version 3.12.3 found at "/usr/bin/python3"
    native/windows-registry install:
    native/windows-registry install: gyp info spawn /usr/bin/python3
    native/windows-registry install: gyp info spawn args [
    native/windows-registry install: gyp info spawn args '/home/lesley/.cache/node/corepack/v1/pnpm/12.0.0/dist/node_modules/node-gyp/gyp/gyp_main.py',
    native/windows-registry install: gyp info spawn args 'binding.gyp',
    native/windows-registry install: gyp info spawn args '-f',
    native/windows-registry install: gyp info spawn args 'make',
    native/windows-registry install: gyp info spawn args '-I',
    native/windows-registry install: gyp info spawn args '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/native/windows-registry/build/config.gypi',
    native/windows-registry install: gyp info spawn args '-I',
    native/windows-registry install: gyp info spawn args '/home/lesley/.cache/node/corepack/v1/pnpm/12.0.0/dist/node_modules/node-gyp/addon.gypi',
    native/windows-registry install: gyp info spawn args '-I',
    native/windows-registry install: gyp info spawn args '/home/lesley/.cache/node-gyp/24.19.0/include/node/common.gypi',
    native/windows-registry install: gyp info spawn args '-Dlibrary=shared_library',
    native/windows-registry install: gyp info spawn args '-Dvisibility=default',
    native/windows-registry install: gyp info spawn args '-Dnode_root_dir=/home/lesley/.cache/node-gyp/24.19.0',
    native/windows-registry install: gyp info spawn args '-Dnode_gyp_dir=/home/lesley/.cache/node/corepack/v1/pnpm/12.0.0/dist/node_modules/node-gyp',
    native/windows-registry install: gyp info spawn args '-Dnode_lib_file=/home/lesley/.cache/node-gyp/24.19.0/<(target_arch)/node.lib',
    native/windows-registry install: gyp info spawn args '-Dmodule_root_dir=/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/native/windows-registry',
    native/windows-registry install: gyp info spawn args '-Dnode_engine=v8',
    native/windows-registry install: gyp info spawn args '--depth=.',
    native/windows-registry install: gyp info spawn args '--no-parallel',
    native/windows-registry install: gyp info spawn args '--generator-output',
    native/windows-registry install: gyp info spawn args 'build',
    native/windows-registry install: gyp info spawn args '-Goutput_dir=.'
    native/windows-registry install: gyp info spawn args ]
    native/windows-registry install: gyp info spawn make
    native/windows-registry install: gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
    native/windows-registry install: make: Entering directory '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/native/windows-registry/build'
    native/windows-registry install: TOUCH Release/obj.target/orca_windows_registry.stamp
    native/windows-registry install: make: Leaving directory '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/native/windows-registry/build'
    native/windows-registry install: gyp info ok
    native/windows-registry install: Done
    . postinstall$ node config/scripts/rebuild-native-deps.mjs
    . postinstall: [rebuild] Skipping optional Electron rebuild modules: cpu-features
    . postinstall: [rebuild] Native modules already load in Electron; skipping rebuild.
    . postinstall: Done
    . prepare$ husky
    . prepare: node:fs:3177
    . prepare: binding.copyFile(
    . prepare: ^
    . prepare:
    . prepare: Error: EACCES: permission denied, copyfile '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/node_modules/.pnpm/husky@9.1.7/node_modules/husky/husky' -> '.husky//h'
    . prepare: at Object.copyFileSync (node:fs:3177:11)
    . prepare: at default (file:///data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/node_modules/.pnpm/husky@9.1.7/node_modules/husky/index.js:21:4)
    . prepare: at file:///data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/node_modules/.pnpm/husky@9.1.7/node_modules/husky/bin.js:26:16
    . prepare: at ModuleJob.run (node:internal/modules/esm/module_job:439:25)
    . prepare: at async node:internal/modules/esm/loader:643:26
    . prepare: at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5) {
    . prepare: errno: -13,
    . prepare: code: 'EACCES',
    . prepare: syscall: 'copyfile',
    . prepare: path: '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/node_modules/.pnpm/husky@9.1.7/node_modules/husky/husky',
    . prepare: dest: '.husky/
    /h'
    . prepare: }
    . prepare:
    . prepare: Node.js v24.19.0
    . prepare: Failed, and Scope: all 2 workspace projects
    ✓ Lockfile passes supply-chain policies (verified 7h ago)
    Lockfile is up to date, resolution step is skipped
    Already up to date
    native/windows-registry install$ node-gyp rebuild
    native/windows-registry install: gyp info it worked if it ends with ok
    native/windows-registry install: gyp info using node-gyp@12.3.0
    native/windows-registry install: gyp info using node@24.19.0 | linux | x64
    native/windows-registry install: gyp info find Python using Python version 3.12.3 found at "/usr/bin/python3"
    native/windows-registry install:
    native/windows-registry install: gyp info spawn /usr/bin/python3
    native/windows-registry install: gyp info spawn args [
    native/windows-registry install: gyp info spawn args '/home/lesley/.cache/node/corepack/v1/pnpm/12.0.0/dist/node_modules/node-gyp/gyp/gyp_main.py',
    native/windows-registry install: gyp info spawn args 'binding.gyp',
    native/windows-registry install: gyp info spawn args '-f',
    native/windows-registry install: gyp info spawn args 'make',
    native/windows-registry install: gyp info spawn args '-I',
    native/windows-registry install: gyp info spawn args '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/native/windows-registry/build/config.gypi',
    native/windows-registry install: gyp info spawn args '-I',
    native/windows-registry install: gyp info spawn args '/home/lesley/.cache/node/corepack/v1/pnpm/12.0.0/dist/node_modules/node-gyp/addon.gypi',
    native/windows-registry install: gyp info spawn args '-I',
    native/windows-registry install: gyp info spawn args '/home/lesley/.cache/node-gyp/24.19.0/include/node/common.gypi',
    native/windows-registry install: gyp info spawn args '-Dlibrary=shared_library',
    native/windows-registry install: gyp info spawn args '-Dvisibility=default',
    native/windows-registry install: gyp info spawn args '-Dnode_root_dir=/home/lesley/.cache/node-gyp/24.19.0',
    native/windows-registry install: gyp info spawn args '-Dnode_gyp_dir=/home/lesley/.cache/node/corepack/v1/pnpm/12.0.0/dist/node_modules/node-gyp',
    native/windows-registry install: gyp info spawn args '-Dnode_lib_file=/home/lesley/.cache/node-gyp/24.19.0/<(target_arch)/node.lib',
    native/windows-registry install: gyp info spawn args '-Dmodule_root_dir=/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/native/windows-registry',
    native/windows-registry install: gyp info spawn args '-Dnode_engine=v8',
    native/windows-registry install: gyp info spawn args '--depth=.',
    native/windows-registry install: gyp info spawn args '--no-parallel',
    native/windows-registry install: gyp info spawn args '--generator-output',
    native/windows-registry install: gyp info spawn args 'build',
    native/windows-registry install: gyp info spawn args '-Goutput_dir=.'
    native/windows-registry install: gyp info spawn args ]
    native/windows-registry install: gyp info spawn make
    native/windows-registry install: make: Entering directory '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/native/windows-registry/build'
    native/windows-registry install: gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
    native/windows-registry install: TOUCH Release/obj.target/orca_windows_registry.stamp
    native/windows-registry install: make: Leaving directory '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/native/windows-registry/build'
    native/windows-registry install: gyp info ok
    native/windows-registry install: Done
    . postinstall$ node config/scripts/rebuild-native-deps.mjs
    . postinstall: [rebuild] Skipping optional Electron rebuild modules: cpu-features
    . postinstall: [rebuild] Native modules already load in Electron; skipping rebuild.
    . postinstall: Done
    . prepare$ husky
    . prepare: node:fs:3177
    . prepare: binding.copyFile(
    . prepare: ^
    . prepare:
    . prepare: Error: EACCES: permission denied, copyfile '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/node_modules/.pnpm/husky@9.1.7/node_modules/husky/husky' -> '.husky//h'
    . prepare: at Object.copyFileSync (node:fs:3177:11)
    . prepare: at default (file:///data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/node_modules/.pnpm/husky@9.1.7/node_modules/husky/index.js:21:4)
    . prepare: at file:///data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/node_modules/.pnpm/husky@9.1.7/node_modules/husky/bin.js:26:16
    . prepare: at ModuleJob.run (node:internal/modules/esm/module_job:439:25)
    . prepare: at async node:internal/modules/esm/loader:643:26
    . prepare: at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5) {
    . prepare: errno: -13,
    . prepare: code: 'EACCES',
    . prepare: syscall: 'copyfile',
    . prepare: path: '/data/opt/revive/orca_serve/state/factory/workspaces/fork/bug-chat-ui-showing-out-of-sequence-messages/node_modules/.pnpm/husky@9.1.7/node_modules/husky/husky',
    . prepare: dest: '.husky/
    /h'
    . prepare: }
    . prepare:
    . prepare: Node.js v24.19.0
    . prepare: Failed pass (or CI will cover; local preferred)

@greptile-apps

greptile-apps Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

[Medium risk] Reorders pending chat messages and adjusts clock-skew tolerance.

The PR does not appear safe to merge until queued follow-ups retain their correct position as transcript rows replace optimistic echoes.

Findings

  1. P1 Queued prompts change position ▶

Summary

The PR changes optimistic prompt ordering, queued follow-up classification, and clock-skew tolerance in native chat.

  • Pending prompts now sort before the streaming reply they trigger; queued follow-ups sort after the active reply.
  • The latest queue-position adjustment still relies on which optimistic echoes remain visible, so transcript catch-up can put a later follow-up on the wrong side of a streaming reply.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[Queued sends] --> B[Hide echoes represented by transcript rows]
  B --> C[Assign surviving indices]
  C --> D[Classify queued state]
  D --> E[Sort with streaming preview]
Loading

Reviews (6) · Last reviewed commit: "fix(native-chat): keep subsequent follow..."

Comment thread src/renderer/src/components/native-chat/native-chat-pending.ts Outdated
Comment thread src/renderer/src/components/native-chat/native-chat-session-assembler.ts Outdated
@greptile-apps

greptile-apps Bot commented Sep 30, 2026

Copy link
Copy Markdown

Comments Outside Diff

These findings could not be posted inline.

  • P1 Clock skew still reorders prompts src/renderer/src/components/native-chat/native-chat-session-assembler.ts:106 ▶

    Pending prompts use the renderer’s clock, but this comparator sorts them against messages timestamped by the host without accounting for clock differences. If the host clock is ahead, a new prompt can appear above older history; if the renderer clock is ahead, a reply can still appear above the pending prompt it answers.

@coderabbitai

coderabbitai Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Important

Review skipped

We couldn't safely recover the incremental review. No full review was started, and the last reviewed checkpoint was preserved. Retry later, or explicitly request a full review by commenting @coderabbitai full review.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Pending sends now record queue state and working-epoch data. Timestamp matching for pending sends and launch prompts allows a clock-skew interval for epoch-millisecond timestamps. The resolved view sorts pending messages with the streaming message, and the comparator ranks queued messages after the streaming preview.

Priority: ➖ Normal

Severity of issue fixed: Medium

Merge Risk: 🔵 Low · up to 279ca

The chat-ordering specification should be corrected to distinguish active prompts from queued follow-ups. The identified runtime edge case is narrow and recoverable, so the change is mergeable with owner awareness.

Security architecture risk: 🔵 Low · up to 279ca

The inspected changes do not expand agent permissions or access to other conversations. A narrow reconciliation case can mistake recent history for a new send and remove its delivery-failure feedback. The impact appears localized, but broader runtime coverage remains incomplete.

Retained concerns

  • Low · reliability · inferred: A send recorded during initial transcript loading has no captured message boundary. At head, an older identical user turn within the new 2,000 ms allowance, followed by a non-user message, can satisfy reconciliation and permanently remove the new pending entry. Subsequent rejection or lost-acknowledgment callbacks cannot update the removed entry, weakening delivery-failure recovery feedback. The base excluded those older timestamped turns. This is an inferred, localized lifecycle failure, not a demonstrated authorization bypass.

Security review details

Security Blast Radius

  • inferred — The demonstrated propagation is to pending-send presentation and delivery feedback within the affected pane-and-agent scope. The inspected changes do not establish increased tenant, service, data-store, or environment authority.

Trust Boundaries and Controls

  • observed — In the inspected PTY path, user text and attachment paths pass through the existing disabled-state and target checks before transport is initiated. The changed optimistic callback runs afterward and records local metadata; it does not select a new target or grant execution authority.

Resilience and Maintainability Implications

  • inferred — Premature pending-entry cleanup can suppress local failure feedback, but the inspected transport handle is tracked separately. The reconciliation concern therefore does not demonstrate cancellation of the actual send or bypass of an execution control.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 41.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 12 functions across 9 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main changes: chronological ordering of pending prompts and tolerance for cross-host clock skew.
Description check ✅ Passed The description explains the user-visible problem, changes, rationale, linked issue, and added tests. It also reports test results and cross-platform considerations. The visual-proof section names a c…
Linked Issues check ✅ Passed Issue #23851 requires prompts to appear before the responses they trigger. compareMessages assigns ordinary pending prompts rank 0, streaming previews rank 1, and explicitly queued prompts rank 2. `…
Out of Scope Changes check ✅ Passed The queue-state tracking, timestamp matching tolerance, pruning tests, and specification support prompt ordering and prevent clock skew from misclassifying or stranding prompts for #23851. The reviewe…
Full details: Docstring Coverage

Explanation

Docstring coverage is 41.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 12 functions across 9 files. (1 skipped: 1 unsupported.)

  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.

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

@coderabbitai coderabbitai 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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Advanced

Run ID: 8d631c0a-8c67-4e22-afaf-45d6f41a2d09

📥 Commits

Reviewing files that changed from the base of the PR and between 373d951 and 3e70f377b9404ce854e24682e1109379e11f9073.

📒 Files selected for processing (7)
  • docs/review-evidence/23851-chat-ui-out-of-sequence-messages.md
  • src/renderer/src/components/native-chat/NativeChatResolvedView.tsx
  • src/renderer/src/components/native-chat/native-chat-message-grouping.test.ts
  • src/renderer/src/components/native-chat/native-chat-pending.test.ts
  • src/renderer/src/components/native-chat/native-chat-pending.ts
  • src/renderer/src/components/native-chat/native-chat-session-assembler.test.ts
  • src/renderer/src/components/native-chat/native-chat-session-assembler.ts

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

Comment thread src/renderer/src/components/native-chat/native-chat-session-assembler.ts Outdated

@pullfrog pullfrog 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.

Important

The rank collapse fixes the prompt that triggered the current reply but inverts the mirrored case: a prompt queued while the agent is still streaming now sorts above the streaming preview and renders before the answer to the previous turn. See inline.

Reviewed changes

  • Pending prompts sort chronologically — compareMessages drops messageSortRank's rank-2 tier; pending/launch echoes now share rank 0 and order by timestamp, with only NATIVE_CHAT_STREAMING_ID at rank 1.
  • View echo order — NativeChatResolvedView concatenates pendingMessages before the streaming bubble (cosmetic, since the list re-sorts via compareMessages).
  • Clock-skew slack — native-chat-pending.ts applies LIFECYCLE_CLOCK_SKEW_SLACK_MS to client-sent boundaries (pending matching, launch-prompt pruning), each gated by the existing epoch-ms > 1e11 check; server transcript boundaries stay strict.
  • Tests — new/updated cases across the three native-chat test files.
  • Evidence doc — new docs/review-evidence/23851-chat-ui-out-of-sequence-messages.md.

ℹ️ Nitpicks

  • isPendingMessageId (native-chat-pending.ts:277) and isLaunchPromptMessageId (native-chat-pending.ts:341) lost their only production caller when the session-assembler import was removed; they are now referenced only by their own tests. Remove both helpers and their test blocks unless a near-term consumer is planned.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

Comment thread src/renderer/src/components/native-chat/native-chat-session-assembler.ts Outdated
Comment thread docs/review-evidence/23851-chat-ui-out-of-sequence-messages.md Outdated
@LesleyMurfin
LesleyMurfin force-pushed the ai/bug-chat-ui-showing-out-of-sequence-messages branch from 3e70f37 to cc56e17 Compare September 30, 2026 21:17
@LesleyMurfin

Copy link
Copy Markdown
Contributor Author

PR Update & Review Response Summary

Comment thread src/renderer/src/components/native-chat/native-chat-pending.ts Outdated

@pullfrog pullfrog 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.

ℹ️ No critical issues — the previously flagged queued-send inversion is fixed. One bounded ordering gap and a few minor notes inline.

Reviewed changes (delta since the prior pullfrog review at 3e70f377)

  • Queued sends rank again — re-introduced messageSortRank with message.queued → rank 2 and NATIVE_CHAT_STREAMING_ID → rank 1, addressing the inverted queued case raised last review.
  • queued threaded end to end — onOptimisticSend computes queued from isWorking || liveWorking || streamingText, record stores it on the pending entry, and pendingSendsAsMessages emits it on the echo.
  • Strict sentAt boundary restored — messageIsAfterPendingTimestamp drops the clock-skew slack it carried at 3e70f377; new tests pin the strict >= / > split.
  • View tail ordering — the pending echoes and streaming bubble are sorted with compareMessages before being appended.
  • Tests — new/updated cases across the three native-chat suites plus use-native-chat-pending-delivery.test.tsx.

ℹ️ Nitpicks

  • record's third parameter is typed NativeChatRecordPendingOptions | boolean (use-native-chat-pending-delivery.ts:51), but no caller passes a boolean — only { queued } is ever used. Drop the union arm.
  • This commit deleted the two-line comment in messageIsAfterPendingTimestamp explaining why a local send time is inclusive (>=) while a transcript boundary is exclusive (>). It is load-bearing rationale for a change this PR is specifically about; restore it.
  • The PR description still says skew slack was added to client sentAt boundaries, but that slack was removed here and the new tests assert the strict behavior. Update the description so it matches the code.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

@pullfrog pullfrog 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.

Important

The new dynamic queued check subtracts the renderer clock from the execution host's clock, so on a host whose clock lags, the prompt that triggered the current turn is flagged queued and renders below its own streaming reply — the #23851 inversion, now confined to remote/paired hosts.

Reviewed changes (delta since the prior pullfrog review at cc56e17d)

  • Dynamic queued evaluation — pendingSendsAsMessages accepts { liveWorking, hookWorkingEpoch } and decides queued live from entry.sentAt >= hookWorkingEpoch, replacing the send-time latch and resolving the prior "queued latch never clears" finding.
  • First-send skew slack — messageIsAfterPendingTimestamp applies LIFECYCLE_CLOCK_SKEW_SLACK_MS when afterMessageId === null, and launch-prompt matching/pruning gain the same slack, so a first/launch prompt whose transcript row trails the renderer clock still prunes; paged-out transcript boundaries stay strict.
  • Tests — new cases in native-chat-pending.test.ts, native-chat-session-assembler.test.ts, native-chat-message-grouping.test.ts, and use-native-chat-pending-delivery.test.tsx.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

Comment thread src/renderer/src/components/native-chat/native-chat-pending.ts Outdated
@LesleyMurfin

Copy link
Copy Markdown
Contributor Author

Update: Resolution of Cross-Clock Dynamic Queuing & Review Feedback

Commit 876eb552921 addresses the remaining review points and nitpicks:

  1. Eliminated Cross-Clock Subtraction in Queued Evaluation:

    • NativeChatPendingSend now tracks queuedBehindWorkingEpoch?: number | null, captured at send time from hookWorkingEpoch (host clock domain).
    • In pendingSendsAsMessages, a pending message is classified as queued if and only if liveWorking && entry.queuedBehindWorkingEpoch != null && hookWorkingEpoch === entry.queuedBehindWorkingEpoch.
    • Both sides now compare strictly within the host's clock domain, completely eliminating cross-clock subtraction and ensuring that host clock lag (e.g. on remote/SSH hosts) cannot falsely flag the triggering prompt as queued.
  2. Nitpicks Addressed:

    • Dropped the | boolean union arm from options?: NativeChatRecordPendingOptions in use-native-chat-pending-delivery.ts.
    • Restored the load-bearing comment in messageIsAfterPendingTimestamp documenting why local send time is inclusive (>=) while transcript-clock boundary is exclusive (>).
    • Updated the PR description to align with the final implementation.
  3. Verification:

    • Added unit test explicitly verifying that a host clock lagging by 30 seconds (sentAt = T, hookWorkingEpoch = T - 30_000) does not flag the triggering prompt as queued and preserves Rank 0 sorting before the streaming preview.
    • All 220 native chat test suites and TypeScript typecheck pass 100% clean.

Comment thread src/renderer/src/components/native-chat/native-chat-pending.ts Outdated

@pullfrog pullfrog 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.

✅ No new issues found.

Reviewed changes (delta since the prior pullfrog review at 88d0eee)

  • Queued state moved into the host clock domain — onOptimisticSend now records queuedBehindWorkingEpoch (the live hookWorkingEpoch) and pendingSendsAsMessages marks a send queued only while liveWorking and the live epoch still equals that stored epoch, replacing the renderer-sentAt vs host-epoch subtraction that inverted remote/paired prompts.
  • record option shape tightened — the | boolean arm was dropped from NativeChatRecordPendingOptions; the pending entry now always carries queuedBehindWorkingEpoch.
  • Restored rationale comment — the inclusive-vs-strict boundary comment in messageIsAfterPendingTimestamp is back.
  • Tests — the dynamic-queued case was reworked for the epoch-equality rule, plus a regression case asserting a triggering prompt stays rank 0 when the host clock lags; the delivery test covers queuedBehindWorkingEpoch persistence.

The prior inline concern (cross-clock subtraction) is correctly resolved: both sides of the equality are host-clock values, so the triggering prompt stays rank 0 and a queued follow-up still ranks below its active turn's streaming preview.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

Comment thread src/renderer/src/components/native-chat/native-chat-pending.ts Outdated

@pullfrog pullfrog 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.

Important

The new isSubsequentQueuedSend heuristic infers "this follow-up is now the active turn" from its position among visible echoes, but the active send's echo is exactly the one that vanishes when its transcript user row lands. I confirmed both mis-sorts with a failing unit test — the multi-follow-up ordering can invert in either direction.

Reviewed changes (delta since the prior pullfrog review at 876eb55)

  • Later queued follow-ups stay queued — pendingSendsAsMessages now also marks an entry with a stored queuedBehindWorkingEpoch as queued when it is not the first surviving echo, so a second follow-up keeps rank 2 once the first becomes the active turn.
  • Test coverage — the dynamic-queued test asserts the first follow-up unqueues and the second stays queued when the epoch advances.
  • Spec artifact — adds specs/23851-chat-ui-out-of-sequence-messages.md describing the change.

ℹ️ Nitpicks

  • specs/23851-chat-ui-out-of-sequence-messages.md reads as agent planning scratch (Step-by-Step, Expert Maintainer Audit, Notes for Next Agent) and introduces a new top-level specs/ directory with no other entries. A prior review flagged the same material under docs/review-evidence/ as worth dropping or folding into the PR description.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

Comment thread src/renderer/src/components/native-chat/native-chat-pending.ts Outdated
@LesleyMurfin

Copy link
Copy Markdown
Contributor Author

Update: Resolution of Queued Follow-Up Ordering Position (Commit 8f11f21476c)

This update addresses the review feedback regarding follow-up prompt positioning:

  1. Pre-Filter Active Queued Send Determination:

    • Replaced post-filter survivingIndex with pending.findIndex(...) directly over the pre-filter incoming pending array.
    • Identified the active turn by position in the stable input array, decoupling active prompt selection from visibility/glue filtering.
  2. Scenarios Resolved:

    • Scenario A (First follow-up user row lands in transcript): When turn 1's user row lands and hides its echo, the subsequent follow-up retains its queued classification (queued: true) and continues sorting after the streaming preview for turn 1.
    • Scenario B (Older echo lingers): When an older echo remains visible, the now-active follow-up is correctly recognized by its position in pending and unqueued to Rank 0, sorting before its own streaming reply.
  3. Verification:

    • Unit tests added to native-chat-pending.test.ts covering both Scenario A and Scenario B.
    • Vitest suite passing 100% (70/70 tests in native-chat-pending.test.ts, 28/28 in assembler & grouping tests).

@pullfrog pullfrog 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.

✅ No new issues found.

Reviewed changes (delta since the prior pullfrog review at c0f604ff)

  • Active queued send selected before filtering — pendingSendsAsMessages now picks the active send by its position in the incoming pending array (the first entry with a stale queuedBehindWorkingEpoch) rather than its index among surviving echoes, so the active echo's classification no longer flips when its own transcript row hides it.
  • Queued follow-ups survive pruning and a null epoch — a stale-epoch send stays queued while the last transcript row is an unanswered user turn whose timestamp is at/after its stored epoch, and a queued send stays queued when hookWorkingEpoch is null; otherwise the earliest stale-epoch send becomes the active turn.
  • Tests — new native-chat-pending-queued.test.ts pins the post-prune, older-echo-lingering, null-epoch, and lagging-host-clock cases; the five touched native-chat suites pass locally (108 tests).

The prior [!IMPORTANT] finding is resolved: both mis-sorts it described (a follow-up surviving after its predecessor's echo hides, and a now-active follow-up while an older echo lingers) are now decided by the send's stable pre-filter position, with the transcript-tail check covering the prune window.

Pullfrog  | View workflow run | Using deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

@LesleyMurfin

Copy link
Copy Markdown
Contributor Author

@CodeRabbit full review

@coderabbitai

coderabbitai Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 27301a16-01aa-427e-9a7f-d9dab720ecf4
📥 Commits

Reviewing files that changed from the base of the PR and between afa81dc and 279cade.

📒 Files selected for processing (10)
  • specs/23851-chat-ui-out-of-sequence-messages.md
  • src/renderer/src/components/native-chat/NativeChatResolvedView.tsx
  • src/renderer/src/components/native-chat/native-chat-message-grouping.test.ts
  • src/renderer/src/components/native-chat/native-chat-pending-queued.test.ts
  • src/renderer/src/components/native-chat/native-chat-pending.test.ts
  • src/renderer/src/components/native-chat/native-chat-pending.ts
  • src/renderer/src/components/native-chat/native-chat-session-assembler.test.ts
  • src/renderer/src/components/native-chat/native-chat-session-assembler.ts
  • src/renderer/src/components/native-chat/use-native-chat-pending-delivery.test.tsx
  • src/renderer/src/components/native-chat/use-native-chat-pending-delivery.ts

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

Comment on lines +5 to +21
In `src/renderer/src/components/native-chat/native-chat-session-assembler.ts`, `messageSortRank` previously classified messages into artificial tiers where pending user prompts were ranked 2 and streaming previews were ranked 1. This caused pending user prompts to sort after streaming previews and assistant responses. Additionally, clock skew between host and client could cause launch prompt pruning to fail.

The fix unifies user message sorting precedence:
1. Pending user prompts and authoritative messages sort by timestamp chronologically.
2. The active streaming preview sits directly after the user prompt that triggered it.
3. Pending send and launch prompt pruning are tolerant of cross-host clock skew.
4. Adversarial review identified and resolved two edge cases in `pendingSendsAsMessages`:
- Handled post-pruning React state cycle: when a prior follow-up is pruned from `pending` after landing in the transcript, subsequent follow-up sends remain queued behind the in-progress transcript turn.
- Handled null `hookWorkingEpoch`: when an agent is live-working (e.g. scrape/terminal turn), explicitly queued sends remain queued even if `hookWorkingEpoch` is not yet available.

All 108 targeted Vitest tests pass, web typecheck is clean, oxlint has 0 issues, and `check:code-quality:changed` passes with 0 findings.
## Summary

Restore strict chronological ordering in `compareMessages` and message assembly:
1. Pending user prompts must not sort after subsequent assistant responses or streaming previews. User prompts appear before the agent response that answers them.
2. In `compareMessages`, chronological timestamps take precedence for user prompts so pending user prompts sort by submission order.
3. The streaming preview (`NATIVE_CHAT_STREAMING_ID`) with `null` timestamp sorts directly after the user prompt that triggered it, never before the user prompt.

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

sed -n '1,70p' specs/23851-chat-ui-out-of-sequence-messages.md
sed -n '90,118p' src/renderer/src/components/native-chat/native-chat-session-assembler.ts

Repository: stablyai/orca

Length of output: 5962


🏁 Script executed:

git diff --unified=50 ed462b2caa5e280d6a56b2f9c6fed1b2bc2f86db 279cadef0267182ac0bb2eb1b632f047c167fe86 -- specs/23851-chat-ui-out-of-sequence-messages.md src/renderer/src/components/native-chat/native-chat-session-assembler.ts src/renderer/src/components/native-chat/native-chat-pending.ts src/renderer/src/components/native-chat/use-native-chat-pending-delivery.ts src/renderer/src/components/native-chat/native-chat-session-assembler.test.ts src/renderer/src/components/native-chat/native-chat-pending-queued.test.ts
printf '\\n--- spec complete ---\\n'
nl -ba specs/23851-chat-ui-out-of-sequence-messages.md | sed -n '1,120p'
printf '\\n--- relevant implementation declarations ---\\n'
rg -n -C 8 'messageSortRank|pendingSendsAsMessages|hookWorkingEpoch|queued:' src/renderer/src/components/native-chat/native-chat-session-assembler.ts src/renderer/src/components/native-chat/native-chat-pending.ts src/renderer/src/components/native-chat/use-native-chat-pending-delivery.ts

Repository: stablyai/orca

Length of output: 42023


🤖 get_repo_knowledge executed:

get_repo_knowledge stablyai/orca /tmp/coderabbit-repo-knowledge/stablyai-orca-89dc44e4/learnings /tmp/coderabbit-repo-knowledge/stablyai-orca-89dc44e4/conventions

Length of output: 47809


🏁 Script executed:

printf '%s\\n' '--- base comparator ---'
git show ed462b2caa5e280d6a56b2f9c6fed1b2bc2f86db:src/renderer/src/components/native-chat/native-chat-session-assembler.ts | nl -ba | sed -n '88,120p'
printf '%s\\n' '--- head comparator ---'
git show 279cadef0267182ac0bb2eb1b632f047c167fe86:src/renderer/src/components/native-chat/native-chat-session-assembler.ts | nl -ba | sed -n '88,120p'
printf '%s\\n' '--- head pending queue logic ---'
git show 279cadef0267182ac0bb2eb1b632f047c167fe86:src/renderer/src/components/native-chat/native-chat-pending.ts | nl -ba | sed -n '258,330p'
printf '%s\\n' '--- spec lines ---'
git show 279cadef0267182ac0bb2eb1b632f047c167fe86:specs/23851-chat-ui-out-of-sequence-messages.md | nl -ba | sed -n '1,70p'
printf '%s\\n' '--- applicable guidance candidates ---'
rg --files -g 'AGENTS.md' -g 'CONTRIBUTING*' -g '*spec*' specs . 2>/dev/null | sed -n '1,80p'

Repository: stablyai/orca

Length of output: 16459


🏁 Script executed:

nl -ba AGENTS.md | sed -n '1,220p'

Repository: stablyai/orca

Length of output: 15296


Correct the ordering summary to distinguish active and queued prompts.

The description of the previous ranks is accurate. The current summary is too broad: compareMessages still compares ranks before transcript order, so queued prompts sort after the streaming preview. Update the spec to describe the retained rank tiers. The queue-state notes are supported by the implementation.

Suggested spec wording
-The fix unifies user message sorting precedence:
-1. Pending user prompts and authoritative messages sort by timestamp chronologically.
-2. The active streaming preview sits directly after the user prompt that triggered it.
+`compareMessages` keeps three rank tiers. Messages other than queued prompts and the streaming preview rank 0; the streaming preview ranks 1; queued prompts rank 2. The comparator applies transcript order only within each rank.
+1. The triggering prompt sorts before the streaming preview.
+2. Prompts queued while the agent is working sort after the preview.
@@
-Restore strict chronological ordering in `compareMessages` and message assembly:
-1. Pending user prompts must not sort after subsequent assistant responses or streaming previews. User prompts appear before the agent response that answers them.
-2. In `compareMessages`, chronological timestamps take precedence for user prompts so pending user prompts sort by submission order.
-3. The streaming preview (`NATIVE_CHAT_STREAMING_ID`) with `null` timestamp sorts directly after the user prompt that triggered it, never before the user prompt.
+Preserve rank-first ordering in `compareMessages` and message assembly:
+1. The triggering prompt sorts before the streaming preview; queued prompts sort after it.
+2. `compareMessages` compares rank before transcript order.
+3. The streaming preview (`NATIVE_CHAT_STREAMING_ID`) ranks after the triggering prompt and before queued prompts.
@@
-   - Adjust `messageSortRank` and `compareMessages` in `native-chat-session-assembler.ts` so pending user messages sort by their chronological timestamp.
+   - Adjust `messageSortRank` and `compareMessages` in `native-chat-session-assembler.ts` to preserve the active-prompt, preview, and queued-prompt ranks.

…clock skew (stablyai#23851)

Active pending/launch echoes sort with ordinary transcript order so the
prompt that started a turn stays above its streaming reply. Mid-turn
follow-ups set queued:true and wait behind the live preview.

Wall-clock first-send and launch matching accept LIFECYCLE_CLOCK_SKEW_SLACK_MS
when comparing local sentAt/createdAt to host timestamps; same-host
transcript boundaries stay strict. Rebased onto current main and keep
empty-transcript session claims when recording pending sends.
Mid-turn follow-ups kept queued:true until prune, so after the prior stream
ended they could still sort behind the next streaming reply. Clear queued once
working and stream preview are both idle so remaining pendings rank as ordinary
prompts above any later stream.
@LesleyMurfin
LesleyMurfin force-pushed the ai/bug-chat-ui-showing-out-of-sequence-messages branch from f23f737 to f740321 Compare October 15, 2026 20:28

This branch has not been deployed

No deployments
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.

[Bug] Chat UI showing out of sequence messages

1 participant