Skip to content

fix(runtime): isolate navigation across paired clients - #9664

Merged
OrcaWin merged 6 commits into
mainfrom
OrcaWin/multi-client-active-worktree-isolation
Jul 21, 2026
Merged

OrcaWin merged 6 commits into
mainfrom
OrcaWin/multi-client-active-worktree-isolation

Conversation

@OrcaWin

@OrcaWin OrcaWin commented Jul 21, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Make worktree, session-tab, and terminal-focus navigation caller-local by default for paired runtime and mobile clients.
  • Keep shared runtime topology authoritative while projecting active tab/group state per paired device and runtime server.
  • Add schema-validated caller | host | clients | all navigation intent with live-only explicit follow delivery.
  • Preserve mixed-version safety and intentional CLI/renderer “reveal on host” behavior.

Screenshots

No visual change.

Root cause

Remote worktree activation called the host notifier and broadcast an unscoped client navigation event. Session-tab activation also rewrote the single shared mobileSessionTabsByWorktree active selection, so every subscriber consumed the last writer as navigation. Existing echo suppression stopped a loop but did not establish ownership.

Deterministic reproduction

src/main/runtime/multi-client-navigation-isolation.integration.test.ts starts real OrcaRuntimeRpcServer instances and authenticates independent E2EE WebSocket sessions from distinct pairing offers/device IDs. It covers:

  • host on H, client A on A, client B on B, then A activates A2 without moving B or host;
  • independent session-tab selection plus reconnect;
  • explicit host/client follow intent;
  • crossed A/B clients across two independent servers.

The harness uses message barriers rather than sleeps and exercises the real dispatcher, pairing registry, encrypted WebSocket transport, subscriptions, runtime routing, graph-backed snapshots, and per-device projection.

Run locally on macOS or Linux; Windows and Docker are not required:

pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/multi-client-navigation-isolation.integration.test.ts
pnpm test:e2e:multi-client-navigation

The E2E command builds Orca and its paired web client, launches one real Electron runtime host, and opens two clients in isolated Electron Chromium partitions.

Testing

  • pnpm lint — focused oxlint, React Doctor, max-lines ratchet, and reliability gates pass; the repository-wide switch-exhaustiveness command reports pre-existing errors in untouched skill-freshness-group.tsx and daemon-server.ts.
  • pnpm typecheck
  • pnpm test — proportionate targeted suites were run rather than every repository test.
  • pnpm build — Electron E2E and paired web production builds completed successfully.
  • Added or updated high-quality tests that would catch regressions.

Exact results:

  • Post-review targeted runtime/RPC/renderer/CLI suite: 11 files, 308 passed.
  • Earlier expanded targeted root suite: 1084 passed, 2 skipped.
  • Full mobile suite: 2130 passed, 2 skipped.
  • Local browser E2E: 1 passed in 53.1s (test body 7.3s), using one Electron host and two independently paired clients.
  • Root/mobile typecheck and focused oxlint passed.
  • Web production build/verification, max-lines ratchet, reliability gates, and git diff --check passed.

AI Review Report

Ran $internal-review-until-clean anchored at merge base 0e7b0ac22079f4ab6dba708bb595daaa627e3285, including pre-review and post-fix elegance interrogation, a performance audit, and two adversarial review rounds.

The review checked navigation ownership, paired identity vs. connection identity, reconnect/restart/stale-snapshot behavior, graph fanout, explicit follow routing, mixed versions, session-tab fallback, terminal creation/focus, privacy boundaries, and cross-platform behavior on macOS, Linux, Windows, WSL, and SSH. No platform heuristic, shortcut, label, shell, path, or platform-specific Electron behavior was added.

It validated two CodeRabbit findings and fixed them:

  • paired runtime terminal.focus could still steer the host implicitly; it now uses the central navigation resolver, while intentional CLI/renderer reveals send explicit navigation: 'host';
  • streaming RPC handlers were not given the pairing context already available to one-shot handlers; the dispatcher now forwards it with focused coverage.

It also corrected the selected-group fallback test and added a concise ownership-precedence comment. The final post-fix round found no additional actionable issue.

The final design supersedes PR #9029 rather than reusing it unchanged. #9029 suppresses ordinary host focus but still rewrites/fans out one global active session-tab snapshot, so it needs rework to provide independent client selections.

Security Audit

Reviewed RPC schema validation, authenticated device identity, pairing credentials, transient connection IDs, IPC boundaries, navigation-state disclosure, command/path handling, secrets, and dependency impact.

  • Navigation state is keyed by the revocable paired device ID, never the bearer credential or connection ID.
  • Per-client selection remains memory-only and is removed on pairing revocation or worktree deletion.
  • One paired client receives shared resource topology plus only its own projected selection; explicit follow is live-only and is not persisted/replayed after reconnect.
  • Navigation targets are additive, schema-validated enums and deny paired-client fanout by default.
  • No new subprocess input, path handling, secret storage, dependency, or public network surface was added.

No security follow-up is required for this change.

Notes

  • Stable paired-device state survives transport reconnect while the runtime process remains alive; a server restart falls back deterministically instead of persisting private navigation globally.
  • New clients send legacy-safe notifyClients:false; terminal creation also sends activate:false. New hosts treat older paired clients as caller-local by default.
  • Local/in-process callers retain legacy behavior. Host/client follow remains available only through explicit intent.
  • Docker would add packaging variance but no useful ownership coverage here; the local E2E already uses real Electron runtime, pairing, encryption, WebSockets, and isolated browser storage.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 5776cf76-15bc-459b-9ac7-43565ca81a7e

📥 Commits

Reviewing files that changed from the base of the PR and between 61a7c5f and 6d7914b.

📒 Files selected for processing (17)
  • mobile/app/h/[hostId]/index.tsx
  • mobile/app/h/[hostId]/session/[worktreeId].tsx
  • mobile/app/notification-opt-in.tsx
  • mobile/src/onboarding/legacy-notification-opt-in-destination.ts
  • mobile/src/onboarding/legacy-notification-opt-in-route.test.ts
  • mobile/src/session/ai-vault-resume-preparation.test.ts
  • mobile/src/session/mobile-session-startup-source.test.ts
  • package.json
  • src/main/index.ts
  • src/main/runtime/orca-runtime.test.ts
  • src/main/runtime/orca-runtime.ts
  • src/main/runtime/rpc/methods/terminal.ts
  • src/renderer/src/components/terminal-pane/remote-runtime-pty-transport.test.ts
  • src/renderer/src/components/terminal-pane/remote-runtime-pty-transport.ts
  • src/shared/ai-vault-resume-preparation.test.ts
  • src/shared/ai-vault-resume-preparation.ts
  • src/shared/runtime-types.ts
🚧 Files skipped from review as they are similar to previous changes (10)
  • src/shared/runtime-types.ts
  • mobile/src/session/mobile-session-startup-source.test.ts
  • src/main/runtime/orca-runtime.test.ts
  • src/renderer/src/components/terminal-pane/remote-runtime-pty-transport.test.ts
  • mobile/app/h/[hostId]/index.tsx
  • src/main/index.ts
  • src/renderer/src/components/terminal-pane/remote-runtime-pty-transport.ts
  • src/main/runtime/rpc/methods/terminal.ts
  • mobile/app/h/[hostId]/session/[worktreeId].tsx
  • src/main/runtime/orca-runtime.ts

📝 Walkthrough

Walkthrough

The change introduces explicit runtime navigation targets and paired-device identity propagation through RPC handling. Runtime tab snapshots now maintain per-client selection state, project active tabs independently, and scope idempotency and subscriptions by client. Mobile, renderer, and CLI flows send caller-local activation and selection options, while terminal focus can avoid host navigation. It also adds legacy notification redirects, AI vault resume-preparation handling, web-client packaging fallbacks, and tests for schema validation, reconnects, and multi-client isolation.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.26% which is insufficient. The required threshold is 80.00%. 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 is concise and directly summarizes the main change: isolating navigation across paired clients.
Description check ✅ Passed The description includes all required sections and covers summary, screenshots, testing, AI review, security, and notes.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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.

@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: 2

🧹 Nitpick comments (2)
src/main/runtime/client-session-tab-selection.test.ts (1)

91-111: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Test doesn't actually exercise "fallback within the selected group."

The removed fixture drops group-right (and all browser tabs) entirely, so resolution falls through to the global snapshot.tabs[0] fallback rather than the in-group fallback path (selection.activeTabIdByGroupId[selectedGroup.id] in client-session-tab-selection.ts, lines 79-84) that the test name implies. Consider adding a case where the selected group still exists but only the specific selected tab within it disappears (e.g., a sibling leaf tab), to cover that branch on this isolation-critical helper.

src/main/runtime/client-session-tab-selection.ts (1)

78-107: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Non-obvious fallback chain lacks a "why" comment.

The tab-resolution fallback chain and per-group activeTabId recomputation are logically correct (verified against client-session-tab-selection.test.ts) but involve several layered ?? fallbacks with implicit precedence (previous exact tab → in-group tracked tab → group's first tab → global first tab). A brief comment on why this precedence order exists (e.g., preferring the most specific prior selection before falling back) would help future maintainers, consistent with the rest of the file (e.g., line 149's rationale comment).

As per coding guidelines, "For non-obvious TypeScript code, add a concise comment explaining why the constraint exists, not how the code works."

Source: Coding guidelines


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 20da6655-b0f3-4cf0-ba1b-282678ada5f9

📥 Commits

Reviewing files that changed from the base of the PR and between 995ee88 and 8423dbd.

📒 Files selected for processing (41)
  • mobile/app/h/[hostId]/index.tsx
  • mobile/app/h/[hostId]/session/[worktreeId].tsx
  • mobile/src/session/ai-vault-resume-launch.test.ts
  • mobile/src/session/ai-vault-resume-launch.ts
  • mobile/src/session/mobile-session-startup-source.test.ts
  • mobile/src/session/mobile-session-tab-activation.test.ts
  • mobile/src/session/mobile-session-tab-activation.ts
  • mobile/src/session/pr-ai-triage-launch.test.ts
  • mobile/src/session/pr-ai-triage-launch.ts
  • mobile/src/session/use-mobile-diff-review-send-actions.ts
  • mobile/src/worktree/mobile-worktree-activation-source.test.ts
  • src/main/runtime/client-session-tab-selection.test.ts
  • src/main/runtime/client-session-tab-selection.ts
  • src/main/runtime/multi-client-navigation-isolation.integration.test.ts
  • src/main/runtime/orca-runtime.test.ts
  • src/main/runtime/orca-runtime.ts
  • src/main/runtime/rpc/core.ts
  • src/main/runtime/rpc/dispatcher.ts
  • src/main/runtime/rpc/methods/session-tabs-schemas.test.ts
  • src/main/runtime/rpc/methods/session-tabs-schemas.ts
  • src/main/runtime/rpc/methods/session-tabs.test.ts
  • src/main/runtime/rpc/methods/session-tabs.ts
  • src/main/runtime/rpc/methods/terminal-navigation.test.ts
  • src/main/runtime/rpc/methods/terminal.ts
  • src/main/runtime/rpc/methods/worktree-schemas.test.ts
  • src/main/runtime/rpc/methods/worktree-schemas.ts
  • src/main/runtime/rpc/methods/worktree.test.ts
  • src/main/runtime/rpc/methods/worktree.ts
  • src/main/runtime/runtime-rpc.ts
  • src/renderer/src/components/terminal-pane/remote-runtime-pty-transport.test.ts
  • src/renderer/src/components/terminal-pane/remote-runtime-pty-transport.ts
  • src/renderer/src/lib/worktree-activation-created-agent.test.ts
  • src/renderer/src/lib/worktree-activation-empty-remote.test.ts
  • src/renderer/src/lib/worktree-activation.ts
  • src/renderer/src/runtime/web-runtime-session.test.ts
  • src/renderer/src/runtime/web-runtime-session.ts
  • src/renderer/src/runtime/web-session-tabs-sync.test.ts
  • src/renderer/src/runtime/web-session-tabs-sync.ts
  • src/shared/runtime-navigation.test.ts
  • src/shared/runtime-navigation.ts
  • src/shared/runtime-types.ts

Comment thread src/main/runtime/rpc/dispatcher.ts Resolved
@OrcaWin

OrcaWin commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator Author

Added local browser-level multi-client E2E coverage in dad237565.

The new pnpm test:e2e:multi-client-navigation runner builds the Electron E2E app plus bundled web client, launches one real runtime server/host UI, pairs two distinct runtime devices into isolated Electron Chromium sessions, and drives H / A / B -> A2 through the rendered worktree UI. DOM assertions verify client B remains on B and the host remains on H. It requires neither windows 2, Docker, pairing secrets, a coworker Mac, nor a separate Playwright browser download.

Validation:

  • pnpm test:e2e:multi-client-navigation — 1 passed (56.7s total; test 11.8s)
  • pnpm typecheck — passed
  • touched-file oxlint — passed
  • pnpm check:max-lines-ratchet — passed
  • pnpm check:reliability-gates — passed
  • git diff --check — passed

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