docs(mobile): record Source Control on the generic host lane

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
This commit is contained in:
Jinwoo-H
2026-09-07 15:39:21 -04:00
parent a6c2ee1ea9
commit 6a44e5129c
8 changed files with 23 additions and 37 deletions
@@ -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.
@@ -113,15 +113,15 @@ async function executeSourceControl(args: Deps, request: OnceRequest): Promise<u
args.workspaceAuthority
)
}
if (request.operation !== 'generateCommitMessage') {
throw new MobileWebBrokerError('unsupported_capability')
if (request.operation === 'generateCommitMessage') {
return args.commitMessageGeneration.generate({
requestId: request.requestId,
payload: request.payload,
client: args.connectedClient(),
workspaceAuthority: args.workspaceAuthority
})
}
return args.commitMessageGeneration.generate({
requestId: request.requestId,
payload: request.payload,
client: args.connectedClient(),
workspaceAuthority: args.workspaceAuthority
})
throw new MobileWebBrokerError('unsupported_capability')
}
async function executeSpeech(args: Deps, request: OnceRequest): Promise<unknown> {
@@ -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'
@@ -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'
@@ -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(
@@ -41,28 +41,8 @@ const EXPECTED_ECHO_FIELDS: Record<string, readonly string[]> = {
'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)
})
})
@@ -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(