From fe3868508cc2342449f609af09bdcb04ebbe5d40 Mon Sep 17 00:00:00 2001 From: Jinwoo-H Date: Mon, 14 Sep 2026 02:17:16 -0400 Subject: [PATCH] refactor(mobile): give the one-key unchecked reader a name Four readers were the same three lines: read one property off the reply, wrap it unchecked. `rpcUncheckedMemberReader` is the one-key sibling of the existing `rpcUncheckedPayloadReader`, so the annotation and the closure go away at each site. The pilot's `commitCompareEntriesReader` is converted too, so the helper has no longhand twin left to copy from. No behaviour change: the helper composes the same `rpcReadUnchecked` over `rpcPayloadMember`, including the property-read exception on a null result. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb --- .../mobile-git-read-operations.ts | 26 +++++++------------ .../tasks/mobile-task-runtime-operations.ts | 9 ++----- .../mobile-workspace-source-operations.ts | 19 +++----------- mobile/src/transport/rpc-reader-payload.ts | 8 ++++++ 4 files changed, 24 insertions(+), 38 deletions(-) diff --git a/mobile/src/source-control/mobile-git-read-operations.ts b/mobile/src/source-control/mobile-git-read-operations.ts index e611abe982c..3b815f3eb5b 100644 --- a/mobile/src/source-control/mobile-git-read-operations.ts +++ b/mobile/src/source-control/mobile-git-read-operations.ts @@ -1,6 +1,9 @@ import { bindDeferredRpcOperation, defineRpcOperation } from '../transport/rpc-operation' import type { RpcCompatibleReader } from '../transport/rpc-operation-contract' -import { rpcPayloadMember, rpcUncheckedPayloadReader } from '../transport/rpc-reader-payload' +import { + rpcUncheckedMemberReader, + rpcUncheckedPayloadReader +} from '../transport/rpc-reader-payload' import { readMobileGitStatusResult } from '../session/mobile-diff-review-rpc' import type { MobileGitStatusResult } from './mobile-git-status' @@ -58,27 +61,18 @@ export const gitHistoryRead = bindDeferredRpcOperation( }) ) -const commitCompareEntriesReader: RpcCompatibleReader< - unknown, - 'commit-compare-entries', - unknown -> = (raw) => ({ - compatible: true, - variant: 'commit-compare-entries', - // Keeps the property-read exception the expanded-commit list already relies on: a null result - // throws inside the load, which is what leaves an already-loaded file list alone. - value: rpcPayloadMember(raw, 'entries'), - salvage: { droppedPaths: [], droppedCount: 0 } -}) - -/** A refused compare leaves the row's file list untouched, so refusal is a skip, not a throw. */ +/** + * A refused compare leaves the row's file list untouched, so refusal is a skip, not a throw. The + * member read keeps the property-read exception a null result throws, which is what leaves an + * already-loaded file list alone. + */ export const gitCommitCompareRead = bindDeferredRpcOperation( defineRpcOperation({ name: 'git.commit-compare-entries-or-skip', method: 'git.commitCompare', acceptance: 'success-result-or-skip', barrier: 'after-caller-barrier', - read: commitCompareEntriesReader + read: rpcUncheckedMemberReader('commit-compare-entries', 'entries') }) ) diff --git a/mobile/src/tasks/mobile-task-runtime-operations.ts b/mobile/src/tasks/mobile-task-runtime-operations.ts index 4609ade04c4..c69651af666 100644 --- a/mobile/src/tasks/mobile-task-runtime-operations.ts +++ b/mobile/src/tasks/mobile-task-runtime-operations.ts @@ -1,8 +1,6 @@ import { bindDeferredRpcOperation, defineRpcOperation } from '../transport/rpc-operation' -import type { RpcCompatibleReader } from '../transport/rpc-operation-contract' import { - rpcPayloadMember, - rpcReadUnchecked, + rpcUncheckedMemberReader, rpcUncheckedPayloadReader } from '../transport/rpc-reader-payload' @@ -23,9 +21,6 @@ export const taskRuntimeStatusRead = bindDeferredRpcOperation( }) ) -const persistedUiStateReader: RpcCompatibleReader = (raw) => - rpcReadUnchecked('ui-state-member', rpcPayloadMember(raw, 'ui')) - /** * Persisted UI state, read at the hydration barrier alongside preflight and Linear status. A * refused read leaves the screen on its defaults rather than failing hydration, so it is a skip. @@ -36,7 +31,7 @@ export const taskUiStateRead = bindDeferredRpcOperation( method: 'ui.get', acceptance: 'success-result-or-skip', barrier: 'after-caller-barrier', - read: persistedUiStateReader + read: rpcUncheckedMemberReader('ui-state-member', 'ui') }) ) diff --git a/mobile/src/tasks/mobile-workspace-source-operations.ts b/mobile/src/tasks/mobile-workspace-source-operations.ts index b58304eea3b..3126682c9a1 100644 --- a/mobile/src/tasks/mobile-workspace-source-operations.ts +++ b/mobile/src/tasks/mobile-workspace-source-operations.ts @@ -1,17 +1,13 @@ import { bindDeferredRpcOperation, defineRpcOperation } from '../transport/rpc-operation' -import type { RpcCompatibleReader } from '../transport/rpc-operation-contract' import { - rpcPayloadMember, - rpcReadUnchecked, + rpcUncheckedMemberReader, rpcUncheckedPayloadReader } from '../transport/rpc-reader-payload' // The repo and SSH reads the workspace-create drawer runs: connection state, agent detection, // repo-owned setup hooks, sparse presets and base-branch search. -const sshConnectionStateReader: RpcCompatibleReader = ( - raw -) => rpcReadUnchecked('ssh-connection-state', rpcPayloadMember(raw, 'state')) +const sshConnectionStateReader = rpcUncheckedMemberReader('ssh-connection-state', 'state') /** Connecting an SSH repo before create. The reply's only read field is `state`. */ export const sshRepoConnectRun = bindDeferredRpcOperation( @@ -69,30 +65,23 @@ export const repoSetupHooksRead = bindDeferredRpcOperation( }) ) -const sparsePresetListReader: RpcCompatibleReader = (raw) => - rpcReadUnchecked('sparse-presets', rpcPayloadMember(raw, 'presets')) - export const repoSparsePresetListRead = bindDeferredRpcOperation( defineRpcOperation({ name: 'repo.sparse-preset-list', method: 'repo.sparsePresets', acceptance: 'require-result-or-throw-message', barrier: 'after-caller-barrier', - read: sparsePresetListReader + read: rpcUncheckedMemberReader('sparse-presets', 'presets') }) ) -const savedSparsePresetReader: RpcCompatibleReader = ( - raw -) => rpcReadUnchecked('saved-sparse-preset', rpcPayloadMember(raw, 'preset')) - export const repoSparsePresetSaveRun = bindDeferredRpcOperation( defineRpcOperation({ name: 'repo.save-sparse-preset', method: 'repo.saveSparsePreset', acceptance: 'require-result-or-throw-message', barrier: 'after-caller-barrier', - read: savedSparsePresetReader + read: rpcUncheckedMemberReader('saved-sparse-preset', 'preset') }) ) diff --git a/mobile/src/transport/rpc-reader-payload.ts b/mobile/src/transport/rpc-reader-payload.ts index 07cdebc16a5..4d6a8635007 100644 --- a/mobile/src/transport/rpc-reader-payload.ts +++ b/mobile/src/transport/rpc-reader-payload.ts @@ -25,3 +25,11 @@ export function rpcUncheckedPayloadReader( ): RpcCompatibleReader { return (raw) => rpcReadUnchecked(variant, raw) } + +/** One property off the payload, unchecked. The shape for a call site that cast `result.field`. */ +export function rpcUncheckedMemberReader( + variant: Variant, + key: string +): RpcCompatibleReader { + return (raw) => rpcReadUnchecked(variant, rpcPayloadMember(raw, key)) +}