From 6a44e5129cc7efa118b2db1d3cf3a871760637bd Mon Sep 17 00:00:00 2001 From: Jinwoo-H Date: Mon, 7 Sep 2026 15:39:21 -0400 Subject: [PATCH] docs(mobile): record Source Control on the generic host lane Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb --- .../mobile-hybrid-webview-architecture.md | 10 ++++++-- .../mobile-web-capability-execution-arms.ts | 16 ++++++------- .../src/mobile-web-bridge-client.ts | 2 +- ...bile-web-commit-message-request-client.ts} | 0 ...bile-web-source-control-client-bindings.ts | 2 +- src/shared/mobile-web/bridge-contract.test.ts | 2 +- .../bridge-operation-echo-census.test.ts | 24 ++----------------- .../bridge-operation-registry-census.test.ts | 4 ++-- 8 files changed, 23 insertions(+), 37 deletions(-) rename src/mobile-web/src/{mobile-web-source-control-commit-message-client.ts => mobile-web-commit-message-request-client.ts} (100%) diff --git a/docs/reference/mobile-hybrid-webview-architecture.md b/docs/reference/mobile-hybrid-webview-architecture.md index e606d1253e3..e311fbd2a1a 100644 --- a/docs/reference/mobile-hybrid-webview-architecture.md +++ b/docs/reference/mobile-hybrid-webview-architecture.md @@ -209,8 +209,14 @@ edges still meet the device and keep their measured values. its host-work slot until the host call settles. The Desktop is trusted, so the page addresses host tabs, browser pages and provider sessions by their host ids. Generic subscriptions, native-chat domain actions, file reads, Source - Control reads/watch, session snapshot/feed/actions and terminal metadata use - this path. + Control (status, diff, history, branches, compares, review metadata and the + Git writes), session snapshot/feed/actions and terminal metadata use this + path. A Source Control result the Desktop cannot bound in its own shape is + projected and clipped by a `mobileWeb.sourceControl.*` wrapper before it + crosses the bridge; the writes the page reaches are the Git methods + themselves. Only commit-message generation still runs as a shell operation, + because it outlives the host lane's fifteen-second request deadline and the + page cancels it while it runs. - Decisions behind the generic lane and its 2026-09-07 simplification are in [`plans/2026-09-07-long-lived-mobile-shell-decisions.md`](./plans/2026-09-07-long-lived-mobile-shell-decisions.md). Unmigrated domain operations keep their current adapters until moved. diff --git a/mobile/src/mobile-web/mobile-web-capability-execution-arms.ts b/mobile/src/mobile-web/mobile-web-capability-execution-arms.ts index d69d6b8ca7f..965879f3774 100644 --- a/mobile/src/mobile-web/mobile-web-capability-execution-arms.ts +++ b/mobile/src/mobile-web/mobile-web-capability-execution-arms.ts @@ -113,15 +113,15 @@ async function executeSourceControl(args: Deps, request: OnceRequest): Promise { diff --git a/src/mobile-web/src/mobile-web-bridge-client.ts b/src/mobile-web/src/mobile-web-bridge-client.ts index fdf933c35a9..bbe133c1526 100644 --- a/src/mobile-web/src/mobile-web-bridge-client.ts +++ b/src/mobile-web/src/mobile-web-bridge-client.ts @@ -47,7 +47,7 @@ import { mobileWebReviewClientBindings } from './mobile-web-review-client-bindin import { mobileWebSessionClientBindings } from './mobile-web-session-client-bindings' import { MobileWebSessionRequestClient } from './mobile-web-session-request-client' import { mobileWebSourceControlClientBindings } from './mobile-web-source-control-client-bindings' -import { MobileWebCommitMessageRequestClient } from './mobile-web-source-control-commit-message-client' +import { MobileWebCommitMessageRequestClient } from './mobile-web-commit-message-request-client' import { MobileWebSourceControlRequestClient } from './mobile-web-source-control-request-client' import type { MobileWebSourceControlReviewRequestClient } from './mobile-web-source-control-review-request-client' import { MobileWebSourceControlSyncRequestClient } from './mobile-web-source-control-sync-request-client' diff --git a/src/mobile-web/src/mobile-web-source-control-commit-message-client.ts b/src/mobile-web/src/mobile-web-commit-message-request-client.ts similarity index 100% rename from src/mobile-web/src/mobile-web-source-control-commit-message-client.ts rename to src/mobile-web/src/mobile-web-commit-message-request-client.ts diff --git a/src/mobile-web/src/mobile-web-source-control-client-bindings.ts b/src/mobile-web/src/mobile-web-source-control-client-bindings.ts index ec29a063b3b..ba3172d129f 100644 --- a/src/mobile-web/src/mobile-web-source-control-client-bindings.ts +++ b/src/mobile-web/src/mobile-web-source-control-client-bindings.ts @@ -1,4 +1,4 @@ -import type { MobileWebCommitMessageRequestClient } from './mobile-web-source-control-commit-message-client' +import type { MobileWebCommitMessageRequestClient } from './mobile-web-commit-message-request-client' import type { MobileWebSourceControlRequestClient } from './mobile-web-source-control-request-client' import type { MobileWebSourceControlSyncRequestClient } from './mobile-web-source-control-sync-request-client' diff --git a/src/shared/mobile-web/bridge-contract.test.ts b/src/shared/mobile-web/bridge-contract.test.ts index cd466fb9fa0..c4d4f0bfda9 100644 --- a/src/shared/mobile-web/bridge-contract.test.ts +++ b/src/shared/mobile-web/bridge-contract.test.ts @@ -169,7 +169,7 @@ describe('mobile web bridge page contract', () => { ).toBe(false) }) - it.each(['branches', 'history', 'branchCompare', 'commitCompare'])( + it.each(['generateCommitMessage', 'cancelCommitMessageGeneration'])( 'accepts the explicit source-control %s operation', (operation) => { expect( diff --git a/src/shared/mobile-web/bridge-operation-echo-census.test.ts b/src/shared/mobile-web/bridge-operation-echo-census.test.ts index 85452ec551b..805a938952e 100644 --- a/src/shared/mobile-web/bridge-operation-echo-census.test.ts +++ b/src/shared/mobile-web/bridge-operation-echo-census.test.ts @@ -41,28 +41,8 @@ const EXPECTED_ECHO_FIELDS: Record = { 'submittedCommentIds', 'workspaceId' ], - 'sourceControl.abort': ['operation', 'previousBranch', 'previousHead', 'workspaceId'], - 'sourceControl.branch': ['branch', 'operation', 'previousBranch', 'previousHead', 'workspaceId'], - 'sourceControl.branchCompare': ['baseRef', 'offset', 'revision', 'workspaceId'], - 'sourceControl.branches': ['workspaceId'], 'sourceControl.cancelCommitMessageGeneration': ['workspaceId'], - 'sourceControl.commit': ['previousHead', 'workspaceId'], - 'sourceControl.commitCompare': ['commitId', 'workspaceId'], - 'sourceControl.discard': ['operation', 'relativePaths.length', 'workspaceId'], - 'sourceControl.fetch': ['operation', 'previousBranch', 'previousHead', 'workspaceId'], 'sourceControl.generateCommitMessage': ['previousHead', 'workspaceId'], - 'sourceControl.history': ['limit', 'workspaceId'], - 'sourceControl.pull': ['operation', 'previousBranch', 'previousHead', 'workspaceId'], - 'sourceControl.push': ['operation', 'previousBranch', 'previousHead', 'workspaceId'], - 'sourceControl.rebase': ['operation', 'previousBranch', 'previousHead', 'workspaceId'], - 'sourceControl.reviewDiff': ['relativePath', 'scope', 'workspaceId'], - 'sourceControl.reviewLink': ['workspaceId'], - 'sourceControl.reviewLinkUpdate': ['workspaceId'], - 'sourceControl.reviewMetadata': ['workspaceId'], - 'sourceControl.reviewMetadataUpdate': ['workspaceId'], - 'sourceControl.stage': ['operation', 'relativePaths.length', 'workspaceId'], - 'sourceControl.unstage': ['operation', 'relativePaths.length', 'workspaceId'], - 'sourceControl.upstream': ['workspaceId'], 'task.loadLinearDetail': ['issue.targetId'], 'task.loadLinearIssue': ['issue.targetId'], 'task.projectTable': ['project', 'selectedView.id'], @@ -296,7 +276,7 @@ describe('mobile web bridge operation echo census', () => { ) expect(Object.keys(EXPECTED_ECHO_FIELDS).filter((key) => !registered.has(key))).toEqual([]) - expect(Object.keys(EXPECTED_ECHO_FIELDS).length).toBeGreaterThanOrEqual(49) + expect(Object.keys(EXPECTED_ECHO_FIELDS).length).toBeGreaterThanOrEqual(29) }) it('guards the page workspace handle on every workspace-scoped echo it records', () => { @@ -304,6 +284,6 @@ describe('mobile web bridge operation echo census', () => { fields.some((field) => field === 'workspaceId') ) - expect(workspaceScoped.length).toBeGreaterThanOrEqual(40) + expect(workspaceScoped.length).toBeGreaterThanOrEqual(20) }) }) diff --git a/src/shared/mobile-web/bridge-operation-registry-census.test.ts b/src/shared/mobile-web/bridge-operation-registry-census.test.ts index 8fc802d9ec8..e25d3a8b19c 100644 --- a/src/shared/mobile-web/bridge-operation-registry-census.test.ts +++ b/src/shared/mobile-web/bridge-operation-registry-census.test.ts @@ -30,7 +30,7 @@ describe('mobile web bridge operation registry census', () => { } expect(files.length).toBeGreaterThanOrEqual(40) - expect(named.size).toBeGreaterThanOrEqual(126) + expect(named.size).toBeGreaterThanOrEqual(118) expect([...named].filter((pair) => !registered.has(pair))).toEqual([]) }) @@ -61,7 +61,7 @@ describe('mobile web bridge operation registry census', () => { } } - expect(pairs.size).toBeGreaterThanOrEqual(126) + expect(pairs.size).toBeGreaterThanOrEqual(118) expect([...pairs].filter(([, schemas]) => schemas.size !== 1).map(([key]) => key)).toEqual([]) expect([...pairs.keys()].filter((key) => !registered.has(key))).toEqual([]) expect(