Skip to content

fix(mobile): phone server rows follow the desktop's other-client and sleeping filters - #28819

Merged
Jinwoo-H merged 6 commits into
mainfrom
fix/mobile-server-row-visibility
Oct 15, 2026
Merged

Jinwoo-H merged 6 commits into
mainfrom
fix/mobile-server-row-visibility

Conversation

@Jinwoo-H

@Jinwoo-H Jinwoo-H commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 12 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​616 $\color{#cf222e}{\Huge{\mathbf{−}}}$​61 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​555
Prod 37 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​231 $\color{#cf222e}{\Huge{\mathbf{−}}}$​72 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​159

ELI5

Your phone's workspace list should show exactly what your desktop's sidebar shows. For workspaces on remote Orca servers it didn't.

  • The phone ignored the desktop's "Hide other-client workspaces" setting.
  • It judged "sleeping" by what the server alone could see. So a workspace with a browser or chat tab open on your desktop looked asleep on the phone.

Now the desktop marks the server workspaces its sidebar hides, and counts its own open tabs as activity. The phone follows both.

The setting also now means what it says: it hides other people's workspaces. Workspaces you create from your own phone stay visible, on the desktop and on the phone.

What Changed

Before, on Jinwoo's real setup:

  • windows 2 (120 server workspaces): his desktop had created 10. The server reported all 10 inactive, so the phone's "Hide sleeping" removed them. The phone meanwhile showed 3 active workspaces that another person's device had created.
  • m4 air (90 server workspaces): his desktop had created none. The phone still showed 28 active workspaces from other people's devices.

After:

  • A phone's workspace is recorded as its owner's. When a phone creates a workspace, the machine that runs it records the phone's owner as the creator:

    • For a phone paired straight to that machine, the creator is that machine itself.
    • For a phone a desktop relays to a server, the creator is that desktop's device.

    The "Hide other-client workspaces" rule itself is unchanged; it moves to src/shared/workspace-creator-visibility.ts as isWorkspaceOwnedBySomeoneElse. Because phones now record their owner, the user's own phone workspaces stay visible. This also changes the desktop: workspaces made from your own phone are no longer hidden by this filter. Nothing else reads the phone's own device id from that record; every reader was checked.

  • Server workspaces on the phone. When the desktop passes a server's workspace list to the phone (MobileRelayHostCatalog.worktrees), it changes two things on each row:

    • It adds desktopOtherClient: true when its sidebar hides the row as someone else's. This is only sent while that setting is on, and it uses the desktop's own device id on that server.
    • It sets the existing hasHostSidebarActivity flag to true when the desktop's saved session has a browser tab or native-chat tab open in that workspace. The phone's "Hide sleeping" and its status dot both read this flag, so they follow the desktop with no phone change.
  • The desktop's own workspaces on the phone.

    • worktree.ps adds the same desktopOtherClient mark for phones paired straight to this computer. It never adds it for another desktop's relayed phone.
    • It now counts the same session-tab signals as server rows, through one shared function (src/shared/workspace-session-tab-activity.ts). This changes one thing for every worktree.ps reader: a workspace whose only open tab is a native chat now counts as active, which matches the desktop sidebar. That affects the phone, the orca worktree ps CLI, and the order rows sort in. Browser tabs saved under a worktree:-prefixed key are now recognised too.
  • On the phone, the only change is dropping rows marked desktopOtherClient. Marked rows are still sent, so notification links and workspace lineage keep working.

What the desktop's main process sees, compared with the sidebar. The sidebar treats a workspace as awake if it has any of these: a live terminal, a browser tab, a native-chat tab, or a running agent.

  • For server workspaces, terminals and agents run on the server, and the server's own flag already covers them.
  • Browser and chat tabs exist only on the desktop, so the main process reads them from its saved session. That session is saved with a short delay, so a tab opened a moment ago can take a few seconds to count.

Why

  • Record the owner at creation. Only the machine that runs a workspace knows whether a phone is one it relays for a desktop (parentDeviceId in its device registry). Recording the owner there means:

    • The rule did not have to change.
    • Every viewer agrees.
    • An older desktop paired with an updated server also keeps its phone's workspaces.

    An earlier version of this PR added a separate onBehalfOf field and an in-memory fallback for older servers. Review showed both were extra moving parts, and the fallback made the phone disagree with the desktop sidebar, so both are gone.

  • Mark rows instead of sending the setting. The setting is deliberately kept off paired clients (src/shared/pairing-local-ui-fields.ts). The phone also couldn't apply it, because the rule needs the desktop's device id on each server and the desktop's saved tabs.

  • Reuse the existing activity flag. Folding the desktop's tab activity into hasHostSidebarActivity keeps "Hide sleeping" and the status dot consistent without a new wire field.

  • Compatibility.

    • An old phone ignores desktopOtherClient and shows what it showed before. It does get the improved activity flag.
    • A new phone talking to an old desktop gets no marks and behaves as today.
    • An old server records the relayed phone's own device id as creator. Workspaces a phone creates there are hidden by this filter, on the desktop as today and now on the phone too, until the server updates.
  • Workspaces created before this change. Workspaces a directly paired phone created before this change stay hidden on the desktop, as today. They are now hidden on the phone too. There is no device-registry fallback for them. Jinwoo's desktop has none: all 3,743 of its saved workspace records have either no creator or the desktop itself as creator.

Linked Issue

None. Internal parity fix for the phone-mirrors-desktop project.

Visual Proof

N/A for screenshots: there is no new UI. The visible change is which rows the existing list shows, and their status dot. The end-to-end test below compares the phone's rows with the rows the real desktop sidebar draws.

Testing

  • New end-to-end test tests/e2e/paired-mobile-desktop-mirror-workspace-visibility.spec.ts. It runs a real headless orca serve, a real paired desktop (background launch), and a phone protocol client paired to that desktop. The server has three workspaces: one created on the server itself, one by the desktop, and one by the phone through the desktop.

    • With "Hide other-client workspaces" on, only the server-created workspace is marked. The phone's filtered rows equal the server rows the desktop sidebar renders.
    • The desktop's workspace has its server terminal closed, so the phone's status dot for it reads inactive. Opening a browser tab on the desktop turns that dot active. With "Hide sleeping" on, the phone's rows again equal the sidebar's.
    • It passes locally on macOS, along with the existing paired-mobile-desktop-mirror.spec.ts.
    • With the activity change disabled, the test fails at the status-dot step (expected active, received inactive). On main it cannot pass, because the marks do not exist there.
  • Unit tests:

    • The rule, against the owner shapes phones now record: own, own phone, another client, created on the server, older phone records, no creator, unknown pairing.
    • The creation-time owner: a directly paired phone, a relayed phone, a paired desktop, and the machine's own caller.
    • The relay marks: setting on or off, unknown pairing, browser and chat activity, and another host's session being ignored.
    • The worktree.ps marks: only this computer's own phones, setting off, other callers.
    • The shared session-tab function, the phone's filterWorktrees, and the existing renderer tests for the moved rule.
  • pnpm tc, mobile tsc, check:code-quality:changed, oxlint and the mobile page-closure tests pass. The closure count did not move.

  • Not verified on a physical phone or emulator. The phone side is covered by unit tests, and the end-to-end test runs the phone's own filter and status functions.

  • I manually tested these changes locally

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

Review

An Opus bug review and an Opus design review were done before opening. A further review covered the simplification. The CodeRabbit thread about the unread-badge cache is answered: the cache compares every field the rule reads.

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.

Notes

  • SSH and servers: the server records who owns each workspace. The desktop only adds its own view on top and never decides on the server's behalf.
  • Cross-platform: no new path handling. Saved-session keys are matched to server rows with the existing workspace-id normalisation.

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)

…sleeping filters

A phone created through a desktop now records whom it acted for, so the
desktop's Hide other-client workspaces filter keeps the user's own phone
workspaces (locally and on servers) and hides only other people's.
The desktop relay marks each server row its sidebar would hide, and the
rows its own browser or chat tabs keep awake; the phone applies both.
@coderabbitai

coderabbitai Bot commented Oct 14, 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: 0ed41370-3bc1-4ad3-8826-f62e3c10a455
📥 Commits

Reviewing files that changed from the base of the PR and between 3766792 and 1bee4f0.

📒 Files selected for processing: 1
  • config/scripts/ci-shard-timings.json

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

📝 Walkthrough

The change centralizes workspace ownership checks in a shared module and updates renderer filters to use them. RPC and desktop relay paths add ownership and activity metadata to worktree rows. Mobile filtering excludes rows marked as belonging to another client. Shared tab and session helpers identify workspace activity from browser and structured unified tabs.

Priority: ➖ Normal

Merge Risk: ⚪ Minimal · up to 1bee4

No actionable merge risk was established in the reviewed change. Workspace visibility markers and activity reach the mobile filters on supported paths; the noted legacy-server limitation concerns runtimes that do not support delegated-phone relay.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 27.78% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 36 functions across 51 files. (1 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description check Passed The description is complete and clearly explains the user impact, implementation, rationale, compatibility considerations, testing, visual-proof exception, and checklist status. It states that no link…
Title check Passed The title clearly and concisely describes the main change: mobile server rows now follow the desktop’s other-client and sleeping filters.
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: Docstring Coverage

Explanation

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

  • Fix all pre-merge checks with AI
  • 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.

@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: 490601eb-e71d-44cf-97bd-6fc95b0a95d5
📥 Commits

Reviewing files that changed from the base of the PR and between d09605e and d188cfb.

📒 Files selected for processing: 51
  • config/scripts/ci-shard-timings.json
  • mobile/src/worktree/workspace-list-sections.test.ts
  • mobile/src/worktree/workspace-list-sections.ts
  • mobile/src/worktree/workspace-list-types.ts
  • src/main/ipc/runtime-environment-mobile-relay-hosts.ts
  • src/main/runtime/mobile-desktop-relay/delegated-phone-grant-cache.ts
  • src/main/runtime/mobile-desktop-relay/mobile-desktop-relay-hosts.ts
  • src/main/runtime/mobile-desktop-relay/mobile-desktop-relay.ts
  • src/main/runtime/mobile-desktop-relay/mobile-relay-host-catalog.test.ts
  • src/main/runtime/mobile-desktop-relay/mobile-relay-host-catalog.ts
  • src/main/runtime/orca-runtime-pty-foreground-process-reads.ts
  • src/main/runtime/rpc/core.ts
  • src/main/runtime/rpc/dispatcher-stream-options.ts
  • src/main/runtime/rpc/methods/worktree-catalog-methods.ts
  • src/main/runtime/rpc/workspace-creator-context.test.ts
  • src/main/runtime/rpc/workspace-creator-context.ts
  • src/main/runtime/rpc/worktree-ps-other-client-marks.test.ts
  • src/main/runtime/rpc/worktree-ps-other-client-marks.ts
  • src/main/runtime/runtime-rpc/runtime-rpc-pairing.ts
  • src/main/runtime/runtime-rpc/runtime-rpc-websocket-dispatch.ts
  • src/renderer/src/components/activity/activity-scope-filter.ts
  • src/renderer/src/components/activity/use-agent-pane-threads.ts
  • src/renderer/src/components/native-chat/StructuredAgentSessionPaneOverlayLayer.tsx
  • src/renderer/src/components/native-chat/native-chat-tab-directory.ts
  • src/renderer/src/components/native-chat/structured-agent-registered-agent-surface.test.ts
  • src/renderer/src/components/native-chat/structured-agent-session-tabs.ts
  • src/renderer/src/components/native-chat/structured-attention-dispatch.test.ts
  • src/renderer/src/components/native-chat/structured-attention-surface.ts
  • src/renderer/src/components/sidebar/use-visible-workspace-kanban-worktree-ids.ts
  • src/renderer/src/components/sidebar/visible-worktree-options-from-state.ts
  • src/renderer/src/components/sidebar/visible-worktrees.test.ts
  • src/renderer/src/components/sidebar/visible-worktrees.ts
  • src/renderer/src/components/sidebar/workspace-creator-visibility.test.ts
  • src/renderer/src/components/sidebar/worktree-list/listing/use-filters.ts
  • src/renderer/src/components/sidebar/worktree-list/listing/use-host-visible-scope.ts
  • src/renderer/src/components/sidebar/worktree-list/listing/use-visible-worktrees.ts
  • src/renderer/src/components/use-worktree-jump-palette-worktrees.ts
  • src/renderer/src/hooks/agent-auto-ack-targets.ts
  • src/renderer/src/lib/running-agent-targets.ts
  • src/renderer/src/lib/unread-badge-count-selector.ts
  • src/renderer/src/lib/unread-badge-count.ts
  • src/renderer/src/store/slices/runtime-status.test.ts
  • src/shared/mobile-relay-hosts-contract.ts
  • src/shared/runtime-worktree-contracts.ts
  • src/shared/structured-agent-session-tab.ts
  • src/shared/workspace-creator-provenance.ts
  • src/shared/workspace-creator-visibility.test.ts
  • src/shared/workspace-creator-visibility.ts
  • src/shared/workspace-session-tab-activity.ts
  • src/shared/worktree/types.ts
  • tests/e2e/paired-mobile-desktop-mirror-workspace-visibility.spec.ts
💤 Files with no reviewable changes: 1
  • src/renderer/src/components/sidebar/workspace-creator-visibility.test.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.

…tab activity into the host flag

A phone now records its owner as the creator (this host for a directly
paired phone, the relaying desktop for a delegated one), so the shared rule
is unchanged and onBehalfOf is gone. The relay ORs the desktop's saved
browser/chat tabs into hasHostSidebarActivity, so the phone's status dot
follows too, and local worktree.ps counts the same signals. The old-server
fallback is removed.
@Jinwoo-H

Copy link
Copy Markdown
Contributor Author

Visual proof for this PR is on #28850, under "Visual proof (combined build)": #28850 (comment)

It was captured on one build of #28850 (stacked on this PR), with an Android emulator, a desktop and one test orca serve server. With Hide other-client workspaces and Hide sleeping on in the desktop, the phone list matches the desktop sidebar: the server-created workspace is hidden, and the desktop-created and phone-created ones show. #28824's fixes are not in that build.

# Conflicts:
#	config/scripts/ci-shard-timings.json
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