From 1d950ab0e0fcda5d68e93fbb985ea7e903819e00 Mon Sep 17 00:00:00 2001 From: Jinwoo-H Date: Wed, 9 Sep 2026 20:27:11 -0400 Subject: [PATCH] Generate pinned settings slice from PR 19675 and main callers Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb --- mobile/rpc-foundation/settings-19675.json | 1132 +++++++++++++++++++++ mobile/scripts/rpc-artifact-io.mts | 38 + mobile/scripts/rpc-slice-manifest.mts | 142 +++ 3 files changed, 1312 insertions(+) create mode 100644 mobile/rpc-foundation/settings-19675.json create mode 100644 mobile/scripts/rpc-artifact-io.mts create mode 100644 mobile/scripts/rpc-slice-manifest.mts diff --git a/mobile/rpc-foundation/settings-19675.json b/mobile/rpc-foundation/settings-19675.json new file mode 100644 index 00000000000..c4adddb60ff --- /dev/null +++ b/mobile/rpc-foundation/settings-19675.json @@ -0,0 +1,1132 @@ +{ + "schemaVersion": 1, + "prHead": "dc423947f48c9a0f694f48995aae5dcf817b1e35", + "baseline": "e80fae0c4d4d70424d52eebe383c57b2291b9daa", + "diffSha256": "c368b849e83867b1c7712ef4be9d1412df8b969756caee79ac85e3478119294a", + "changedFiles": [ + "mobile/app/about.tsx", + "mobile/app/browser-settings.tsx", + "mobile/app/connection-log.tsx", + "mobile/app/h/[hostId]/accounts.tsx", + "mobile/app/native-chat-settings.tsx", + "mobile/app/notifications.tsx", + "mobile/app/settings.tsx", + "mobile/app/troubleshoot.tsx", + "mobile/app/voice-settings.tsx", + "mobile/src/accounts/default-host-account-operations.ts", + "mobile/src/accounts/host-account-operations.ts", + "mobile/src/accounts/native-host-account-operations.ts", + "mobile/src/components/MobileRichMarkdownEditor.tsx", + "mobile/src/components/NewWorktreeFormSheet.tsx", + "mobile/src/components/NewWorktreeModal.tsx", + "mobile/src/components/NewWorktreeModalController.tsx", + "mobile/src/components/NewWorktreeModalDrawers.tsx", + "mobile/src/components/SmartWorkspaceSourceDrawer.tsx", + "mobile/src/components/SmartWorkspaceSourceField.tsx", + "mobile/src/components/mobile-rich-markdown-editor-contract.ts", + "mobile/src/components/mobile-rich-markdown-editor-document-body.ts", + "mobile/src/components/mobile-rich-markdown-editor-document-suffix.ts", + "mobile/src/components/mobile-rich-markdown-editor-html.ts", + "mobile/src/components/mobile-rich-markdown-editor-script-primary.ts", + "mobile/src/components/mobile-rich-markdown-editor-script-secondary.ts", + "mobile/src/components/mobile-rich-markdown-editor-script-string.ts", + "mobile/src/components/mobile-rich-markdown-editor-script.ts", + "mobile/src/components/new-worktree-modal-types.ts", + "mobile/src/components/use-mobile-rich-markdown-editor-controller.ts", + "mobile/src/components/use-new-workspace-execution-target.ts", + "mobile/src/components/use-new-workspace-repositories.ts", + "mobile/src/components/use-new-workspace-runtime-context.ts", + "mobile/src/components/use-new-workspace-setup-script.ts", + "mobile/src/device/default-device-operations.ts", + "mobile/src/device/device-operations.ts", + "mobile/src/device/native-device-operations.ts", + "mobile/src/diagnostics/connection-diagnostics-screen-styles.ts", + "mobile/src/diagnostics/connection-diagnostics-screen.tsx", + "mobile/src/diagnostics/connection-diagnostics-view.tsx", + "mobile/src/diagnostics/diagnostics-device-operations.ts", + "mobile/src/diagnostics/native-diagnostics-operations.ts", + "mobile/src/diagnostics/troubleshoot-view.tsx", + "mobile/src/diagnostics/use-troubleshoot-diagnostics.ts", + "mobile/src/files/MobileFileExplorerPanel.tsx", + "mobile/src/files/default-host-file-explorer-operations.ts", + "mobile/src/files/host-file-explorer-operations.ts", + "mobile/src/files/native-host-file-explorer-operations.ts", + "mobile/src/host-screen/host-screen-overlays.tsx", + "mobile/src/session/MobileSessionSheets.tsx", + "mobile/src/session/QuickCommandsSheet.tsx", + "mobile/src/session/default-host-session-browser-operations.ts", + "mobile/src/session/default-host-session-file-operations.ts", + "mobile/src/session/default-host-session-markdown-operations.ts", + "mobile/src/session/default-host-session-native-chat-operations.ts", + "mobile/src/session/default-host-session-operations.ts", + "mobile/src/session/default-host-session-quick-command-operations.ts", + "mobile/src/session/default-host-session-tab-operations.ts", + "mobile/src/session/default-host-session-terminal-file-operations.ts", + "mobile/src/session/default-host-session-terminal-operations.ts", + "mobile/src/session/github-pr-mutations.ts", + "mobile/src/session/host-session-browser-operations.ts", + "mobile/src/session/host-session-file-operations.ts", + "mobile/src/session/host-session-markdown-operations.ts", + "mobile/src/session/host-session-native-chat-operations.ts", + "mobile/src/session/host-session-operations.ts", + "mobile/src/session/host-session-quick-command-operations.ts", + "mobile/src/session/host-session-runtime-capabilities.ts", + "mobile/src/session/host-session-tab-operations.ts", + "mobile/src/session/host-session-terminal-file-operations.ts", + "mobile/src/session/host-session-terminal-operations.ts", + "mobile/src/session/mobile-file-tap-open.ts", + "mobile/src/session/mobile-native-chat-open-file.ts", + "mobile/src/session/mobile-native-chat-operation-target.ts", + "mobile/src/session/mobile-native-chat-send.ts", + "mobile/src/session/native-host-session-browser-operations.ts", + "mobile/src/session/native-host-session-file-operations.ts", + "mobile/src/session/native-host-session-markdown-operations.ts", + "mobile/src/session/native-host-session-native-chat-operations.ts", + "mobile/src/session/native-host-session-operations.ts", + "mobile/src/session/native-host-session-quick-command-operations.ts", + "mobile/src/session/native-host-session-tab-operations.ts", + "mobile/src/session/native-host-session-terminal-file-operations.ts", + "mobile/src/session/native-host-session-terminal-operations.ts", + "mobile/src/session/use-mobile-file-tap-handlers.ts", + "mobile/src/session/use-mobile-native-chat-controller.ts", + "mobile/src/session/use-mobile-native-chat-file-search.ts", + "mobile/src/session/use-mobile-native-chat-readability.ts", + "mobile/src/session/use-mobile-native-chat-session-lane.ts", + "mobile/src/session/use-mobile-native-chat-session.ts", + "mobile/src/session/use-mobile-native-chat-stop.ts", + "mobile/src/session/use-mobile-native-chat-terminal-response-lane.ts", + "mobile/src/session/use-mobile-session-close-actions.ts", + "mobile/src/session/use-mobile-session-content-create-actions.ts", + "mobile/src/session/use-mobile-session-document-readers.ts", + "mobile/src/session/use-mobile-session-feedback-capabilities.ts", + "mobile/src/session/use-mobile-session-file-actions.ts", + "mobile/src/session/use-mobile-session-markdown-actions.ts", + "mobile/src/session/use-mobile-session-native-chat-dictation.ts", + "mobile/src/session/use-mobile-session-screen-state.ts", + "mobile/src/session/use-mobile-session-terminal-input.ts", + "mobile/src/session/use-mobile-session-terminal-runtime.ts", + "mobile/src/session/use-mobile-session-terminal-send-actions.ts", + "mobile/src/session/use-mobile-session-terminal-stream-display.ts", + "mobile/src/session/use-quick-commands.ts", + "mobile/src/settings/about-screen.tsx", + "mobile/src/settings/browser-settings-screen.tsx", + "mobile/src/settings/mobile-settings-menu-items.ts", + "mobile/src/settings/mobile-settings-menu.tsx", + "mobile/src/settings/native-chat-settings-screen.tsx", + "mobile/src/settings/native-notification-settings-operations.ts", + "mobile/src/settings/native-voice-settings-operations.ts", + "mobile/src/settings/notification-settings-operations.ts", + "mobile/src/settings/notification-settings-screen.tsx", + "mobile/src/settings/pending-credential-cleanup-card.tsx", + "mobile/src/settings/settings-menu-screen.tsx", + "mobile/src/settings/voice-settings-operations.ts", + "mobile/src/settings/voice-settings-screen.tsx", + "mobile/src/settings/voice-settings-styles.ts", + "mobile/src/tasks/composer-source-base-resolve.ts", + "mobile/src/tasks/default-host-task-detail-operations.ts", + "mobile/src/tasks/default-host-task-item-file-operations.ts", + "mobile/src/tasks/default-host-task-item-mutation-operations.ts", + "mobile/src/tasks/default-host-task-item-review-operations.ts", + "mobile/src/tasks/default-host-task-linear-operations.ts", + "mobile/src/tasks/default-host-task-list-operations.ts", + "mobile/src/tasks/default-host-task-operations.ts", + "mobile/src/tasks/default-host-task-preference-operations.ts", + "mobile/src/tasks/default-host-task-project-file-operations.ts", + "mobile/src/tasks/default-host-task-project-mutation-operations.ts", + "mobile/src/tasks/default-host-task-project-read-operations.ts", + "mobile/src/tasks/default-host-task-provider-write-operations.ts", + "mobile/src/tasks/default-host-task-read-operations.ts", + "mobile/src/tasks/github-task-detail-projection.ts", + "mobile/src/tasks/host-task-detail-operations.ts", + "mobile/src/tasks/host-task-item-file-operations.ts", + "mobile/src/tasks/host-task-item-mutation-operations.ts", + "mobile/src/tasks/host-task-item-review-operations.ts", + "mobile/src/tasks/host-task-linear-operations.ts", + "mobile/src/tasks/host-task-list-operations.ts", + "mobile/src/tasks/host-task-operations.ts", + "mobile/src/tasks/host-task-preference-operations.ts", + "mobile/src/tasks/host-task-project-file-operations.ts", + "mobile/src/tasks/host-task-project-mutation-operations.ts", + "mobile/src/tasks/host-task-project-payloads.ts", + "mobile/src/tasks/host-task-project-read-operations.ts", + "mobile/src/tasks/host-task-provider-payloads.ts", + "mobile/src/tasks/host-task-provider-write-operations.ts", + "mobile/src/tasks/host-task-read-operations.ts", + "mobile/src/tasks/host-task-runtime-payloads.ts", + "mobile/src/tasks/linear-status-projection.ts", + "mobile/src/tasks/mobile-tasks-filter-pickers.tsx", + "mobile/src/tasks/mobile-tasks-mutation-targets.ts", + "mobile/src/tasks/mobile-tasks-project-row-targets.ts", + "mobile/src/tasks/native-host-task-detail-operations.ts", + "mobile/src/tasks/native-host-task-item-file-operations.ts", + "mobile/src/tasks/native-host-task-item-mutation-operations.ts", + "mobile/src/tasks/native-host-task-item-review-operations.ts", + "mobile/src/tasks/native-host-task-linear-operations.ts", + "mobile/src/tasks/native-host-task-list-operations.ts", + "mobile/src/tasks/native-host-task-operations.ts", + "mobile/src/tasks/native-host-task-preference-operations.ts", + "mobile/src/tasks/native-host-task-project-file-operations.ts", + "mobile/src/tasks/native-host-task-project-mutation-operations.ts", + "mobile/src/tasks/native-host-task-project-read-operations.ts", + "mobile/src/tasks/native-host-task-provider-write-operations.ts", + "mobile/src/tasks/native-host-task-read-operations.ts", + "mobile/src/tasks/setup-hook-trust.ts", + "mobile/src/tasks/smart-source-fan-out.ts", + "mobile/src/tasks/smart-source-paste-intent.ts", + "mobile/src/tasks/smart-source-search-requests.ts", + "mobile/src/tasks/source-workspace-create.ts", + "mobile/src/tasks/use-mobile-tasks-client-settings-actions.tsx", + "mobile/src/tasks/use-mobile-tasks-github-check-file-actions.tsx", + "mobile/src/tasks/use-mobile-tasks-github-reply-merge-actions.tsx", + "mobile/src/tasks/use-mobile-tasks-gitlab-github-status-actions.tsx", + "mobile/src/tasks/use-mobile-tasks-item-detail-loading.tsx", + "mobile/src/tasks/use-mobile-tasks-item-detail-metadata-effects.tsx", + "mobile/src/tasks/use-mobile-tasks-linear-item-actions.tsx", + "mobile/src/tasks/use-mobile-tasks-list-and-detail-effects.tsx", + "mobile/src/tasks/use-mobile-tasks-project-detail-loading.tsx", + "mobile/src/tasks/use-mobile-tasks-project-file-merge-actions.tsx", + "mobile/src/tasks/use-mobile-tasks-project-loading-actions.tsx", + "mobile/src/tasks/use-mobile-tasks-project-metadata-actions.tsx", + "mobile/src/tasks/use-mobile-tasks-project-metadata-loading.tsx", + "mobile/src/tasks/use-mobile-tasks-project-repository-resolution.tsx", + "mobile/src/tasks/use-mobile-tasks-project-review-check-actions.tsx", + "mobile/src/tasks/use-mobile-tasks-project-thread-reply-actions.tsx", + "mobile/src/tasks/use-mobile-tasks-project-workspace-comment-actions.tsx", + "mobile/src/tasks/use-mobile-tasks-provider-load-actions.tsx", + "mobile/src/tasks/use-mobile-tasks-route-and-item-state.tsx", + "mobile/src/tasks/use-mobile-tasks-runtime-hydration.tsx", + "mobile/src/tasks/use-mobile-tasks-task-create-actions.tsx", + "mobile/src/tasks/use-mobile-tasks-task-list-loading.tsx", + "mobile/src/tasks/use-mobile-tasks-task-pagination-actions.tsx", + "mobile/src/tasks/use-mobile-tasks-workspace-create-actions.tsx", + "mobile/src/tasks/use-mobile-tasks-workspace-source-effects.tsx", + "mobile/src/tasks/use-mobile-tasks-workspace-sparse-actions.tsx", + "mobile/src/tasks/use-mobile-tasks-workspace-ssh-state.tsx", + "mobile/src/tasks/use-smart-workspace-source.ts", + "mobile/src/tasks/worktree-create-capability.ts", + "mobile/src/tasks/worktree-create-retry.ts", + "mobile/src/transport/rpc-client.ts", + "mobile/src/worktree/default-host-workspace-creation-operations.ts", + "mobile/src/worktree/host-workspace-creation-operations.ts", + "mobile/src/worktree/host-workspace-host-context.ts", + "mobile/src/worktree/native-host-workspace-creation-operations.ts", + "mobile/src/worktree/native-host-workspace-creation-read-operations.ts", + "mobile/src/worktree/native-host-workspace-creation-source-operations.ts", + "mobile/src/worktree/rpc-workspace-creation-operations.ts", + "mobile/src/worktree/use-retired-worktree-names.ts" + ], + "files": [ + { + "file": "mobile/src/agent-history/MobileAgentSessionHistoryPanel.tsx", + "revision": "e80fae0c4d4d70424d52eebe383c57b2291b9daa", + "sha256": "bcaa4a01f302d7f874035664c1ff0afba4e00deae534ffc3920c60910a10b839" + }, + { + "file": "mobile/src/components/use-new-workspace-create-submit.ts", + "revision": "e80fae0c4d4d70424d52eebe383c57b2291b9daa", + "sha256": "623620f8b3adcd99f128d3f4c93d88e59d20956308c3a448aad6ed1eb4cb1a40" + }, + { + "file": "mobile/src/components/use-new-workspace-runtime-context.ts", + "revision": "e80fae0c4d4d70424d52eebe383c57b2291b9daa", + "sha256": "0e53eb187f37dafa752753e347d2ababd4f4d3bf76f85ef82f901d602dfafc8b" + }, + { + "file": "mobile/src/home/mobile-home-host-requests.ts", + "revision": "e80fae0c4d4d70424d52eebe383c57b2291b9daa", + "sha256": "0758445ede58d1a7746d43c7ac94129a7e30211b29937d7d35a4c6ce3f90e63b" + }, + { + "file": "mobile/src/host-screen/use-host-repo-metadata.ts", + "revision": "e80fae0c4d4d70424d52eebe383c57b2291b9daa", + "sha256": "4f4cf8e57bf6538a97a912e7a874602ef56b198658f32cf375a7903c0bd03ba6" + }, + { + "file": "mobile/src/session/mobile-new-tab-agent-loader.ts", + "revision": "e80fae0c4d4d70424d52eebe383c57b2291b9daa", + "sha256": "647f5adc304c905920a817876b6c70737bdb6302c201549bffc0e49cd1f6931d" + }, + { + "file": "mobile/src/session/use-pr-bot-author-overrides.ts", + "revision": "e80fae0c4d4d70424d52eebe383c57b2291b9daa", + "sha256": "1e77d19923ba02e52d97406fcb3537aeecee9bd56051a2f9734a098456cba42e" + }, + { + "file": "mobile/src/tasks/use-mobile-tasks-runtime-hydration.tsx", + "revision": "e80fae0c4d4d70424d52eebe383c57b2291b9daa", + "sha256": "ac9312352bbe52528aa1ab07142d97f5ffc86afcff2174db1662e894f4e5966d" + }, + { + "file": "mobile/src/tasks/use-mobile-tasks-workspace-create-actions.tsx", + "revision": "e80fae0c4d4d70424d52eebe383c57b2291b9daa", + "sha256": "ac9c60376922e4426df6598759b7cca7640084be8f4805db06d9a642e7b12a4f" + }, + { + "file": "mobile/src/settings/browser-settings-screen.tsx", + "revision": "dc423947f48c9a0f694f48995aae5dcf817b1e35", + "sha256": "0fcb8c8ca60d532458df8fd71381b88898a72569d8843fce223cbc15440b719a" + }, + { + "file": "mobile/src/settings/native-chat-settings-screen.tsx", + "revision": "dc423947f48c9a0f694f48995aae5dcf817b1e35", + "sha256": "a208c17ffbfcd94024be11a42ebed4c0adf422100ecdeccf7da02edc5be71770" + }, + { + "file": "mobile/src/settings/native-notification-settings-operations.ts", + "revision": "dc423947f48c9a0f694f48995aae5dcf817b1e35", + "sha256": "74613213bd535259e2155ee4cefdd797f5e4028a5a06aa160c65fac7d2554253" + }, + { + "file": "mobile/src/session/use-mobile-default-session-view-preference.ts", + "revision": "dc423947f48c9a0f694f48995aae5dcf817b1e35", + "sha256": "b1382bc3ed4c93412417238cd8ab7df89c787d2556de6bdf3f6e4e7450ebc534" + } + ], + "operations": [ + { + "id": "main:mobile/src/agent-history/MobileAgentSessionHistoryPanel.tsx:loadMobileResumeMetadata:settings.get:387", + "file": "mobile/src/agent-history/MobileAgentSessionHistoryPanel.tsx", + "symbol": "loadMobileResumeMetadata", + "line": 387, + "revision": "e80fae0c4d4d70424d52eebe383c57b2291b9daa", + "method": "settings.get", + "kind": "host-rpc", + "options": ["{ timeoutMs: RESUME_RPC_TIMEOUT_MS }"], + "arguments": ["'settings.get'", "undefined", "{ timeoutMs: RESUME_RPC_TIMEOUT_MS }"], + "consumedFields": [ + "Promise.all", + "client\n .sendRequest", + "client\n .sendRequest('folderWorkspace.list', undefined, { timeoutMs: RESUME_RPC_TIMEOUT_MS })\n .catch", + "client\n .sendRequest('projectGroup.list', undefined, { timeoutMs: RESUME_RPC_TIMEOUT_MS })\n .catch", + "client\n .sendRequest('settings.get', undefined, { timeoutMs: RESUME_RPC_TIMEOUT_MS })\n .catch", + "client\n .sendRequest('worktree.ps', { limit: 10000 }, { timeoutMs: RESUME_RPC_TIMEOUT_MS })\n .catch", + "client.sendRequest", + "folderWorkspaceResponse.result", + "folderWorkspaceResponse?.ok", + "folderWorkspaceResult?.folderWorkspaces", + "projectGroupResponse.result", + "projectGroupResponse?.ok", + "projectGroupResult?.groups", + "repoResponse.error", + "repoResponse.error?.message", + "repoResponse.ok", + "repoResponse.result", + "repoResult.repos", + "settingsResponse.result", + "settingsResponse?.ok", + "settingsResult?.settings", + "worktreeResponse.result", + "worktreeResponse?.ok", + "worktreeResult?.worktrees" + ], + "writes": [], + "failures": [ + "folderWorkspaceResult?.folderWorkspaces ?? []", + "projectGroupResult?.groups ?? []", + "repoResponse.error?.message || 'Unable to load workspace metadata.'", + "repoResult.repos ?? []", + "settingsResult?.settings ?? null", + "throw new Error(repoResponse.error?.message || 'Unable to load workspace metadata.')", + "worktreeResult?.worktrees ?? null" + ], + "evidenceScope": "enclosing function; conservative source expressions, not a validated reader contract", + "scenarioIds": [ + "main:mobile/src/agent-history/MobileAgentSessionHistoryPanel.tsx:loadMobileResumeMetadata:settings.get:387:fulfilled", + "main:mobile/src/agent-history/MobileAgentSessionHistoryPanel.tsx:loadMobileResumeMetadata:settings.get:387:refused", + "main:mobile/src/agent-history/MobileAgentSessionHistoryPanel.tsx:loadMobileResumeMetadata:settings.get:387:transport-error" + ], + "scenarioStatus": "planned-step1" + }, + { + "id": "main:mobile/src/components/use-new-workspace-create-submit.ts:create:settings.get:91", + "file": "mobile/src/components/use-new-workspace-create-submit.ts", + "symbol": "create", + "line": 91, + "revision": "e80fae0c4d4d70424d52eebe383c57b2291b9daa", + "method": "settings.get", + "kind": "host-rpc", + "options": [], + "arguments": ["'settings.get'"], + "consumedFields": [ + "(settingsResponse as RpcSuccess).result", + "args.composer", + "args.composer.createSelection", + "args.composer.isNameAutoManaged", + "args.composer.name", + "args.composer.name.trim", + "args.detectedAgentIds", + "args.existingWorktreePaths", + "args.getWorktreeCreateCutoverSupport", + "args.note", + "args.note.trim", + "args.onClose", + "args.onCreated", + "args.retiredWorktreeNames", + "args.runSetup", + "args.runtimeSettings", + "args.selectedAgent", + "args.selectedAgent.id", + "args.setAgentOverridden", + "args.setError", + "args.setRuntimeSettings", + "args.setSelectedAgent", + "args.setupCommand", + "args.setupDecisionChoice", + "args.setupRunPolicy", + "args.setupTrust", + "args.setupTrust.contentHash", + "args.setupTrust.scriptContent", + "args.sshGate", + "args.sshGate.requiresConnection", + "args.transitionDrawer", + "args.trustedOrcaHooks", + "client.sendRequest", + "createInFlightRef.current", + "error.message", + "latestRuntimeSettings?.disabledTuiAgents", + "options.approvedSetupContentHash", + "options.setupOverride", + "result.error", + "result.name", + "result.settings", + "result.worktreeId", + "selectedRepo.displayName", + "selectedRepo.id", + "settingsResponse.ok" + ], + "writes": [ + "setCreating(false)", + "setCreating(true)", + "setSetupTrustPrompt({\n repoId: selectedRepo.id,\n repoName: selectedRepo.displayName,\n scriptContent: args.setupTrust.scriptContent,\n contentHash: args.setupTrust.contentHash,\n previouslyApproved: wasSetupHookPreviouslyApproved(args.trustedOrcaHooks, selectedRepo.id)\n })" + ], + "failures": [ + "!client || !selectedRepo", + "!client || !selectedRepo || createInFlightRef.current", + "args.existingWorktreePaths ?? []", + "args.note.trim() || undefined", + "catch (error) {\n args.setError(error instanceof Error ? error.message : 'Failed to create workspace')\n }", + "catch {\n // The runtime validates the same setting before spawning.\n }", + "normalizeWorkspaceAgent(args.selectedAgent.id) ?? 'blank'", + "trimmedName ||\n getSuggestedCreatureName(\n args.existingWorktreePaths ?? [],\n undefined,\n args.retiredWorktreeNames\n )", + "trimmedName || undefined" + ], + "evidenceScope": "enclosing function; conservative source expressions, not a validated reader contract", + "scenarioIds": [ + "main:mobile/src/components/use-new-workspace-create-submit.ts:create:settings.get:91:fulfilled", + "main:mobile/src/components/use-new-workspace-create-submit.ts:create:settings.get:91:refused", + "main:mobile/src/components/use-new-workspace-create-submit.ts:create:settings.get:91:transport-error" + ], + "scenarioStatus": "planned-step1" + }, + { + "id": "main:mobile/src/components/use-new-workspace-runtime-context.ts:useNewWorkspaceRuntimeContext:settings.get:42", + "file": "mobile/src/components/use-new-workspace-runtime-context.ts", + "symbol": "useNewWorkspaceRuntimeContext", + "line": 42, + "revision": "e80fae0c4d4d70424d52eebe383c57b2291b9daa", + "method": "settings.get", + "kind": "host-rpc", + "options": [], + "arguments": ["'settings.get'"], + "consumedFields": [ + "(\n settingsResult.result as {\n settings: NewWorktreeRuntimeSettings & { visibleTaskProviders?: unknown }\n }\n ).settings", + "(settledSuccess(linearRes)?.result as { connected?: boolean } | undefined)?.connected", + "(settledSuccess(preflightRes)?.result as { glab?: { installed?: boolean } } | undefined)\n ?.glab", + "(settledSuccess(preflightRes)?.result as { glab?: { installed?: boolean } } | undefined)\n ?.glab?.installed", + "(uiResult.result as { ui?: { trustedOrcaHooks?: PersistedTrustedOrcaHooks } }).ui", + "Promise.allSettled", + "client.sendRequest", + "filterAvailableTaskProviders(visibleProviders, {\n gitlabInstalled: glabInstalled,\n linearConnected\n }).filter", + "settingsResult.result", + "settingsValue?.visibleTaskProviders", + "settledSuccess(linearRes)?.result", + "settledSuccess(preflightRes)?.result", + "ui?.trustedOrcaHooks", + "uiResult.result", + "visibleProviders.includes" + ], + "writes": [ + "setAvailableProviders(\n filterAvailableTaskProviders(visibleProviders, {\n gitlabInstalled: glabInstalled,\n linearConnected\n }).filter((provider) => visibleProviders.includes(provider))\n )", + "setRuntimeSettings(settingsValue)", + "setTrustedOrcaHooks(ui?.trustedOrcaHooks ?? {})", + "settledSuccess(linearRes)", + "settledSuccess(preflightRes)", + "settledSuccess(settingsRes)", + "settledSuccess(uiRes)" + ], + "failures": ["ui?.trustedOrcaHooks ?? {}"], + "evidenceScope": "enclosing function; conservative source expressions, not a validated reader contract", + "scenarioIds": [ + "main:mobile/src/components/use-new-workspace-runtime-context.ts:useNewWorkspaceRuntimeContext:settings.get:42:fulfilled", + "main:mobile/src/components/use-new-workspace-runtime-context.ts:useNewWorkspaceRuntimeContext:settings.get:42:refused", + "main:mobile/src/components/use-new-workspace-runtime-context.ts:useNewWorkspaceRuntimeContext:settings.get:42:transport-error" + ], + "scenarioStatus": "planned-step1" + }, + { + "id": "main:mobile/src/home/mobile-home-host-requests.ts:fetchMobileHomeTaskProviders:settings.get:76", + "file": "mobile/src/home/mobile-home-host-requests.ts", + "symbol": "fetchMobileHomeTaskProviders", + "line": 76, + "revision": "e80fae0c4d4d70424d52eebe383c57b2291b9daa", + "method": "settings.get", + "kind": "host-rpc", + "options": [], + "arguments": ["client", "hostId", "'settings.get'"], + "consumedFields": [ + "(settingsResponse.result as { settings?: HomeTaskSettings }).settings", + "Promise.all", + "Promise.all([\n sendSingleFlightRequest(client, hostId, 'settings.get'),\n sendSingleFlightRequest(client, hostId, 'preflight.check'),\n sendSingleFlightRequest(client, hostId, 'linear.status')\n ])\n .then", + "Promise.all([\n sendSingleFlightRequest(client, hostId, 'settings.get'),\n sendSingleFlightRequest(client, hostId, 'preflight.check'),\n sendSingleFlightRequest(client, hostId, 'linear.status')\n ])\n .then(([settingsResponse, preflightResponse, linearResponse]) => {\n if (disposed()) {\n return\n }\n const settings = settingsResponse.ok\n ? (((settingsResponse.result as { settings?: HomeTaskSettings }).settings ??\n {}) as HomeTaskSettings)\n : {}\n const preflight = preflightResponse.ok\n ? (preflightResponse.result as HomePreflightStatus)\n : null\n const linear = linearResponse.ok ? (linearResponse.result as HomeLinearStatus) : null\n const providers = filterAvailableTaskProviders(\n normalizeVisibleTaskProviders(settings.visibleTaskProviders),\n {\n gitlabInstalled: preflight?.glab?.installed === true,\n linearConnected: linear?.connected === true\n }\n )\n setProviders((previous) => ({ ...previous, [hostId]: providers }))\n })\n .catch", + "linear?.connected", + "linearResponse.ok", + "linearResponse.result", + "preflight?.glab", + "preflight?.glab?.installed", + "preflightResponse.ok", + "preflightResponse.result", + "settings.visibleTaskProviders", + "settingsResponse.ok", + "settingsResponse.result" + ], + "writes": [ + "setProviders((previous) =>\n previous[hostId] ? previous : { ...previous, [hostId]: ['github'] }\n )", + "setProviders((previous) => ({ ...previous, [hostId]: providers }))" + ], + "failures": [ + "(settingsResponse.result as { settings?: HomeTaskSettings }).settings ??\n {}" + ], + "evidenceScope": "enclosing function; conservative source expressions, not a validated reader contract", + "scenarioIds": [ + "main:mobile/src/home/mobile-home-host-requests.ts:fetchMobileHomeTaskProviders:settings.get:76:fulfilled", + "main:mobile/src/home/mobile-home-host-requests.ts:fetchMobileHomeTaskProviders:settings.get:76:refused", + "main:mobile/src/home/mobile-home-host-requests.ts:fetchMobileHomeTaskProviders:settings.get:76:transport-error" + ], + "scenarioStatus": "planned-step1" + }, + { + "id": "main:mobile/src/host-screen/use-host-repo-metadata.ts:fetchRepoMetadata:settings.get:124", + "file": "mobile/src/host-screen/use-host-repo-metadata.ts", + "symbol": "fetchRepoMetadata", + "line": 124, + "revision": "e80fae0c4d4d70424d52eebe383c57b2291b9daa", + "method": "settings.get", + "kind": "host-rpc", + "options": [], + "arguments": ["requestClient", "'settings.get'"], + "consumedFields": [ + "(repoResponse as RpcSuccess).result", + "Date.now", + "Promise.all", + "clientRef.current", + "fetchRepoMetadataInFlightRef.current", + "fetchRepoMetadataInFlightRef.current.add", + "fetchRepoMetadataInFlightRef.current.delete", + "fetchRepoMetadataInFlightRef.current.has", + "fetchRepoMetadataPendingRef.current", + "fetchRepoMetadataPendingRef.current.add", + "fetchRepoMetadataPendingRef.current.delete", + "fetchRepoMetadataPendingRef.current.has", + "hostIds.size", + "options.force", + "options.queueIfInFlight", + "repo.badgeColor", + "repo.displayName", + "repo.id", + "repo.repoIcon", + "repoMetadataFetchedAtRef.current", + "repoResponse.ok", + "repoResult.repos", + "repoResult.repos.flatMap", + "repoResult.repos.map", + "requestClient.sendRequest" + ], + "writes": [ + "setCachedRepos(requestHostId, repoResult.repos)", + "setHostLabelById(\n buildHostLabelById({\n sshTargets: readSshTargets(sshTargets),\n hostSettingOverrides: readHostSettingOverrides(hostSettings)\n })\n )", + "setHostPlatform(readHostPlatform(hostPlatform))", + "setRepoColorsByName(\n new Map(\n repoResult.repos.map((repo) => [\n repo.displayName,\n repo.badgeColor || repoColor(repo.displayName)\n ])\n )\n )", + "setRepoHostIdByRepoId(buildRepoHostIdByRepoId(repoResult.repos))", + "setRepoIconsByName(\n new Map(\n repoResult.repos.flatMap((repo) =>\n repo.repoIcon ? [[repo.displayName, repo.repoIcon] as const] : []\n )\n )\n )", + "setRepoIdsByName(new Map(repoResult.repos.map((repo) => [repo.displayName, repo.id])))" + ], + "failures": [ + "!client || connState !== 'connected'", + "!client || connState !== 'connected' || !hostId", + "catch {\n // Repo metadata is decorative; the next refresh can retry.\n }", + "clientRef.current !== requestClient || hostId !== requestHostId", + "clientRef.current !== requestClient || hostId !== requestHostId || !repoResponse.ok", + "repo.badgeColor || repoColor(repo.displayName)" + ], + "evidenceScope": "enclosing function; conservative source expressions, not a validated reader contract", + "scenarioIds": [ + "main:mobile/src/host-screen/use-host-repo-metadata.ts:fetchRepoMetadata:settings.get:124:fulfilled", + "main:mobile/src/host-screen/use-host-repo-metadata.ts:fetchRepoMetadata:settings.get:124:refused", + "main:mobile/src/host-screen/use-host-repo-metadata.ts:fetchRepoMetadata:settings.get:124:transport-error" + ], + "scenarioStatus": "planned-step1" + }, + { + "id": "main:mobile/src/session/mobile-new-tab-agent-loader.ts:loadMobileNewTabAgentOptions:settings.get:26", + "file": "mobile/src/session/mobile-new-tab-agent-loader.ts", + "symbol": "loadMobileNewTabAgentOptions", + "line": 26, + "revision": "e80fae0c4d4d70424d52eebe383c57b2291b9daa", + "method": "settings.get", + "kind": "host-rpc", + "options": [], + "arguments": ["'settings.get'"], + "consumedFields": [ + "(\n (settingsResponse as RpcSuccess).result as {\n settings?: MobileNewTabAgentSettings\n }\n ).settings", + "(detectedResponse as RpcFailure).error", + "(detectedResponse as RpcFailure).error.message", + "(detectedResponse as RpcSuccess).result", + "(settingsResponse as RpcFailure).error", + "(settingsResponse as RpcFailure).error.message", + "(settingsResponse as RpcSuccess).result", + "Promise.all", + "client.sendRequest", + "detectedResponse.ok", + "settingsResponse.ok" + ], + "writes": [], + "failures": [ + "throw new Error((detectedResponse as RpcFailure).error.message)", + "throw new Error((settingsResponse as RpcFailure).error.message)" + ], + "evidenceScope": "enclosing function; conservative source expressions, not a validated reader contract", + "scenarioIds": [ + "main:mobile/src/session/mobile-new-tab-agent-loader.ts:loadMobileNewTabAgentOptions:settings.get:26:fulfilled", + "main:mobile/src/session/mobile-new-tab-agent-loader.ts:loadMobileNewTabAgentOptions:settings.get:26:refused", + "main:mobile/src/session/mobile-new-tab-agent-loader.ts:loadMobileNewTabAgentOptions:settings.get:26:transport-error" + ], + "scenarioStatus": "planned-step1" + }, + { + "id": "main:mobile/src/session/use-pr-bot-author-overrides.ts:usePRBotAuthorOverrides:settings.get:35", + "file": "mobile/src/session/use-pr-bot-author-overrides.ts", + "symbol": "usePRBotAuthorOverrides", + "line": 35, + "revision": "e80fae0c4d4d70424d52eebe383c57b2291b9daa", + "method": "settings.get", + "kind": "host-rpc", + "options": [], + "arguments": ["'settings.get'"], + "consumedFields": [ + "(response as RpcSuccess).result", + "Array.isArray", + "client\n .sendRequest", + "client\n .sendRequest('settings.get')\n .then", + "client\n .sendRequest('settings.get')\n .then((response) => {\n if (stale || !response.ok) {\n return\n }\n const result = (response as RpcSuccess).result as {\n settings?: { prBotAuthorOverrides?: unknown }\n } | null\n const overrides = result?.settings?.prBotAuthorOverrides\n setLogins(\n Array.isArray(overrides)\n ? overrides.filter((login): login is string => typeof login === 'string')\n : []\n )\n })\n .catch", + "overrides.filter", + "response.ok", + "result?.settings", + "result?.settings?.prBotAuthorOverrides", + "sourceClientRef.current" + ], + "writes": [ + "setLogins(\n Array.isArray(overrides)\n ? overrides.filter((login): login is string => typeof login === 'string')\n : []\n )", + "setLogins([])" + ], + "failures": ["!client || connState !== 'connected'", "stale || !response.ok"], + "evidenceScope": "enclosing function; conservative source expressions, not a validated reader contract", + "scenarioIds": [ + "main:mobile/src/session/use-pr-bot-author-overrides.ts:usePRBotAuthorOverrides:settings.get:35:fulfilled", + "main:mobile/src/session/use-pr-bot-author-overrides.ts:usePRBotAuthorOverrides:settings.get:35:refused", + "main:mobile/src/session/use-pr-bot-author-overrides.ts:usePRBotAuthorOverrides:settings.get:35:transport-error" + ], + "scenarioStatus": "planned-step1" + }, + { + "id": "main:mobile/src/tasks/use-mobile-tasks-runtime-hydration.tsx:hydrateTaskState:settings.get:253", + "file": "mobile/src/tasks/use-mobile-tasks-runtime-hydration.tsx", + "symbol": "hydrateTaskState", + "line": 253, + "revision": "e80fae0c4d4d70424d52eebe383c57b2291b9daa", + "method": "settings.get", + "kind": "host-rpc", + "options": [], + "arguments": ["'settings.get'"], + "consumedFields": [ + "(\n uiResponse.result as {\n ui?: {\n taskResumeState?: TaskResumeState\n trustedOrcaHooks?: PersistedTrustedOrcaHooks\n }\n }\n ).ui", + "(settingsResponse.result as { settings?: RuntimeTaskSettings }).settings", + "Promise.all", + "availableProviders.includes", + "client.sendRequest", + "defaultLinearTeamSelectionRef.current", + "defaultRepoSelectionRef.current", + "linearStatus?.connected", + "linearStatusResponse.result", + "nextVisibleProviders.includes", + "preferredProviders.includes", + "preflight?.glab", + "preflight?.glab?.installed", + "preflightResponse.result", + "resume.githubItemsPreset", + "resume.githubItemsQuery", + "resume.githubMode", + "resume.githubProjectHiddenFieldIdsByView", + "resume.linearPreset", + "resume.linearQuery", + "settings.defaultLinearTeamSelection", + "settings.defaultRepoSelection", + "settings.defaultTaskSource", + "settings.defaultTaskViewPreset", + "settings.githubProjects", + "settings.visibleTaskProviders", + "settingsResponse.result", + "status.capabilities", + "status.capabilities?.includes", + "statusResponse.error", + "statusResponse.error.message", + "statusResponse.result", + "taskResumeRef.current", + "uiResponse.result", + "uiState?.taskResumeState", + "uiState?.trustedOrcaHooks" + ], + "writes": [ + "setActionItem(null)", + "setAppliedQuery(nextAppliedQuery)", + "setDefaultGitHubPreset(defaultPreset)", + "setDetailPayload(null)", + "setError('')", + "setError('Update Orca desktop to use Tasks on mobile.')", + "setGithubKind(githubKindFromQuery(githubQuery, preset))", + "setGithubMode(resume.githubMode === 'project' ? 'project' : 'items')", + "setGithubPreset(preset)", + "setGithubProjectHiddenFieldIdsByView(resume.githubProjectHiddenFieldIdsByView ?? {})", + "setGithubProjectSettings(settings.githubProjects ?? EMPTY_GITHUB_PROJECT_SETTINGS)", + "setGithubProjectTable(null)", + "setItems([])", + "setLinearConnected(linearIsConnected)", + "setLinearFilter(nextLinearFilter)", + "setLinearStatusPickerItem(null)", + "setLinearTeams([])", + "setLinearWorkspaces([])", + "setMergeMethodProjectRow(null)", + "setMergeMethodTaskItem(null)", + "setPendingGitHubProjectViewSelection(null)", + "setPendingHostedMerge(null)", + "setPendingHostedStateChange(null)", + "setPendingProjectGitHubMerge(null)", + "setProjectRepoNotInOrca(null)", + "setProjectRowDetail(null)", + "setProjectRowItem(null)", + "setProvider(nextProvider)", + "setQuery(nextQuery)", + "setRuntimeTaskSettings(settings)", + "setSelectedLinearTeamIds(new Set())", + "setSelectedLinearWorkspaceId(null)", + "setShowCreateTargetPicker(false)", + "setShowCreateTask(false)", + "setShowGitHubIssueSourcePicker(false)", + "setShowGitHubKindPicker(false)", + "setShowGitHubPagePicker(false)", + "setShowGitHubPresetPicker(false)", + "setShowGitHubProjectFieldsPicker(false)", + "setShowGitHubProjectPicker(false)", + "setShowGitHubProjectSortPicker(false)", + "setShowGitHubProjectViewPicker(false)", + "setShowGitLabFilterPicker(false)", + "setShowGitLabViewPicker(false)", + "setShowLinearConnect(false)", + "setShowLinearDisplayPicker(false)", + "setShowLinearFilterPicker(false)", + "setShowLinearGroupPicker(false)", + "setShowLinearOrderPicker(false)", + "setShowLinearTeamPicker(false)", + "setShowLinearViewPicker(false)", + "setShowLinearWorkspacePicker(false)", + "setShowProviderPicker(false)", + "setShowRepoPicker(false)", + "setShowSortPicker(false)", + "setTaskStateHydrated(false)", + "setTaskStateHydrated(true)", + "setTasksSupportState({ kind: 'supported', client })", + "setTasksSupportState({ kind: 'unsupported', client })", + "setTrustedOrcaHooks(uiState?.trustedOrcaHooks ?? {})", + "setVisibleProviders(nextVisibleProviders)" + ], + "failures": [ + "(settingsResponse.result as { settings?: RuntimeTaskSettings }).settings ??\n {}", + "resume.githubItemsPreset ?? settings.defaultTaskViewPreset", + "resume.githubItemsQuery ?? ''", + "resume.githubProjectHiddenFieldIdsByView ?? {}", + "resume.linearQuery ?? ''", + "settings.defaultLinearTeamSelection ?? null", + "settings.defaultRepoSelection ?? null", + "settings.githubProjects ?? EMPTY_GITHUB_PROJECT_SETTINGS", + "throw new Error(statusResponse.error.message)", + "uiState?.taskResumeState ?? {}", + "uiState?.trustedOrcaHooks ?? {}" + ], + "evidenceScope": "enclosing function; conservative source expressions, not a validated reader contract", + "scenarioIds": [ + "main:mobile/src/tasks/use-mobile-tasks-runtime-hydration.tsx:hydrateTaskState:settings.get:253:fulfilled", + "main:mobile/src/tasks/use-mobile-tasks-runtime-hydration.tsx:hydrateTaskState:settings.get:253:refused", + "main:mobile/src/tasks/use-mobile-tasks-runtime-hydration.tsx:hydrateTaskState:settings.get:253:transport-error" + ], + "scenarioStatus": "planned-step1" + }, + { + "id": "main:mobile/src/tasks/use-mobile-tasks-workspace-create-actions.tsx:createWorkspace:settings.get:75", + "file": "mobile/src/tasks/use-mobile-tasks-workspace-create-actions.tsx", + "symbol": "createWorkspace", + "line": 75, + "revision": "e80fae0c4d4d70424d52eebe383c57b2291b9daa", + "method": "settings.get", + "kind": "host-rpc", + "options": [], + "arguments": ["'settings.get'"], + "consumedFields": [ + "(\n settingsResponse.result as { settings?: RuntimeTaskSettings }\n ).settings", + "client.sendRequest", + "err.message", + "item.key", + "item.provider", + "item.source", + "item.title", + "latestRuntimeTaskSettings.disabledTuiAgents", + "noteOverride?.trim", + "queryParams.set", + "queryParams.toString", + "response.error", + "response.error.message", + "response.result", + "result.error", + "result.warning", + "result.worktree", + "result.worktree.displayName", + "result.worktree.id", + "router.push", + "settingsResponse.result", + "setupResolution.command", + "setupResolution.decision", + "setupResolution.kind", + "setupResolution.setupTrust", + "setupResolution.setupTrust.contentHash", + "setupResolution.setupTrust.scriptContent", + "setupResolution.source", + "source.branchName", + "source.isCrossRepository", + "source.number", + "source.repoId", + "source.type", + "targetRepo.displayName", + "targetRepo.id", + "workspaceNameOverride?.trim" + ], + "writes": [ + "router.push(\n `/h/${hostId}/session/${encodeURIComponent(result.worktree.id)}?${queryParams.toString()}`\n )", + "setActionItem(null)", + "setCreatingKey(item.key)", + "setCreatingKey(null)", + "setError('')", + "setError(err instanceof Error ? err.message : 'Failed to create workspace')", + "setOrcaYamlTrustPrompt({\n item,\n ...(repoIdOverride ? { repoIdOverride } : {}),\n setupOverride: 'run',\n ...(agentOverride ? { agentOverride } : {}),\n ...(workspaceNameOverride ? { workspaceNameOverride } : {}),\n ...(comment ? { noteOverride: comment } : {}),\n ...(baseBranchOverride ? { baseBranchOverride } : {}),\n ...(branchNameOverride ? { branchNameOverride } : {}),\n ...(sparseCheckoutOverride ? { sparseCheckoutOverride } : {}),\n repoId: targetRepo.id,\n repoName: targetRepo.displayName,\n scriptContent: setupResolution.setupTrust.scriptContent,\n contentHash: setupResolution.setupTrust.contentHash,\n previouslyApproved: wasSetupHookPreviouslyApproved(trustedOrcaHooks, targetRepo.id)\n })", + "setRuntimeTaskSettings(latestRuntimeTaskSettings)", + "setSetupPrompt(null)", + "setSetupPrompt({\n item,\n ...(repoIdOverride ? { repoIdOverride } : {}),\n ...(agentOverride ? { agentOverride } : {}),\n ...(workspaceNameOverride ? { workspaceNameOverride } : {}),\n ...(comment ? { noteOverride: comment } : {}),\n ...(baseBranchOverride ? { baseBranchOverride } : {}),\n ...(branchNameOverride ? { branchNameOverride } : {}),\n ...(sparseCheckoutOverride ? { sparseCheckoutOverride } : {}),\n repoName: targetRepo.displayName,\n command: setupResolution.command,\n source: setupResolution.source\n })", + "setWorkspaceAgent(selectedAgent)", + "setWorkspaceAgentOverridden(false)", + "setWorkspaceCreateDraft(null)" + ], + "failures": [ + "!client || !tasksSupported", + "!client || !tasksSupported || !taskStateHydrated", + "!trimmedWorkspaceName || trimmedWorkspaceName === workspaceLastAutoName", + "(\n settingsResponse.result as { settings?: RuntimeTaskSettings }\n ).settings ?? {}", + "agentOverride === 'blank' ||\n isWorkspaceAgentEnabled(agentOverride, latestRuntimeTaskSettings.disabledTuiAgents)", + "catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to create workspace')\n }", + "catch {\n // Best-effort refresh; the runtime still validates agent availability before spawning.\n }", + "result.worktree.displayName ?? item.title", + "throw new Error(\n item.provider === 'linear'\n ? 'Add a Git repository before creating a Linear workspace.'\n : 'Repository not found.'\n )", + "throw new Error('Selected agent is disabled. Choose an enabled agent before creating.')", + "throw new Error(response.error.message)", + "throw new Error(result.error)", + "workspaceNameOverride?.trim() ?? ''" + ], + "evidenceScope": "enclosing function; conservative source expressions, not a validated reader contract", + "scenarioIds": [ + "main:mobile/src/tasks/use-mobile-tasks-workspace-create-actions.tsx:createWorkspace:settings.get:75:fulfilled", + "main:mobile/src/tasks/use-mobile-tasks-workspace-create-actions.tsx:createWorkspace:settings.get:75:refused", + "main:mobile/src/tasks/use-mobile-tasks-workspace-create-actions.tsx:createWorkspace:settings.get:75:transport-error" + ], + "scenarioStatus": "planned-step1" + }, + { + "id": "pr19675:mobile/src/settings/browser-settings-screen.tsx:selectLinkMode:saveTerminalLinkOpenMode(mode).catch:73", + "file": "mobile/src/settings/browser-settings-screen.tsx", + "symbol": "selectLinkMode", + "line": 73, + "revision": "dc423947f48c9a0f694f48995aae5dcf817b1e35", + "method": "saveTerminalLinkOpenMode(mode).catch", + "kind": "device-preference", + "options": [], + "arguments": ["() =>\n setError('Could not save browser preferences. Try again.')"], + "consumedFields": ["saveTerminalLinkOpenMode(mode).catch"], + "writes": [ + "saveTerminalLinkOpenMode(mode)", + "saveTerminalLinkOpenMode(mode).catch(() =>\n setError('Could not save browser preferences. Try again.')\n )", + "setError('Could not save browser preferences. Try again.')", + "setError(null)", + "setLinkMode(mode)" + ], + "failures": [], + "evidenceScope": "enclosing function; conservative source expressions, not a validated reader contract", + "scenarioIds": [ + "pr19675:mobile/src/settings/browser-settings-screen.tsx:selectLinkMode:saveTerminalLinkOpenMode(mode).catch:73:fulfilled", + "pr19675:mobile/src/settings/browser-settings-screen.tsx:selectLinkMode:saveTerminalLinkOpenMode(mode).catch:73:refused", + "pr19675:mobile/src/settings/browser-settings-screen.tsx:selectLinkMode:saveTerminalLinkOpenMode(mode).catch:73:transport-error" + ], + "scenarioStatus": "planned-step1" + }, + { + "id": "pr19675:mobile/src/settings/browser-settings-screen.tsx:selectLinkMode:saveTerminalLinkOpenMode:73", + "file": "mobile/src/settings/browser-settings-screen.tsx", + "symbol": "selectLinkMode", + "line": 73, + "revision": "dc423947f48c9a0f694f48995aae5dcf817b1e35", + "method": "saveTerminalLinkOpenMode", + "kind": "device-preference", + "options": [], + "arguments": ["mode"], + "consumedFields": ["saveTerminalLinkOpenMode(mode).catch"], + "writes": [ + "saveTerminalLinkOpenMode(mode)", + "saveTerminalLinkOpenMode(mode).catch(() =>\n setError('Could not save browser preferences. Try again.')\n )", + "setError('Could not save browser preferences. Try again.')", + "setError(null)", + "setLinkMode(mode)" + ], + "failures": [], + "evidenceScope": "enclosing function; conservative source expressions, not a validated reader contract", + "scenarioIds": [ + "pr19675:mobile/src/settings/browser-settings-screen.tsx:selectLinkMode:saveTerminalLinkOpenMode:73:fulfilled", + "pr19675:mobile/src/settings/browser-settings-screen.tsx:selectLinkMode:saveTerminalLinkOpenMode:73:refused", + "pr19675:mobile/src/settings/browser-settings-screen.tsx:selectLinkMode:saveTerminalLinkOpenMode:73:transport-error" + ], + "scenarioStatus": "planned-step1" + }, + { + "id": "pr19675:mobile/src/settings/native-chat-settings-screen.tsx:NativeChatSettingsScreen:useMobileDefaultSessionViewPreference:18", + "file": "mobile/src/settings/native-chat-settings-screen.tsx", + "symbol": "NativeChatSettingsScreen", + "line": 18, + "revision": "dc423947f48c9a0f694f48995aae5dcf817b1e35", + "method": "useMobileDefaultSessionViewPreference", + "kind": "device-preference", + "options": [], + "arguments": [], + "consumedFields": [ + "colors.bgRaised", + "colors.textPrimary", + "colors.textSecondary", + "insets.bottom", + "insets.top", + "router.back", + "spacing.lg", + "spacing.sm", + "styles.backButton", + "styles.container", + "styles.groupDescription", + "styles.groupHeading", + "styles.heading", + "styles.row", + "styles.rowContent", + "styles.rowLabel", + "styles.rowSublabel", + "styles.section", + "styles.sectionTopGap", + "styles.topRow" + ], + "writes": ["router.back()", "setDefaultView(next ? 'chat' : 'terminal')"], + "failures": ["onBack ?? (() => router.back())"], + "evidenceScope": "enclosing function; conservative source expressions, not a validated reader contract", + "scenarioIds": [ + "pr19675:mobile/src/settings/native-chat-settings-screen.tsx:NativeChatSettingsScreen:useMobileDefaultSessionViewPreference:18:fulfilled", + "pr19675:mobile/src/settings/native-chat-settings-screen.tsx:NativeChatSettingsScreen:useMobileDefaultSessionViewPreference:18:refused", + "pr19675:mobile/src/settings/native-chat-settings-screen.tsx:NativeChatSettingsScreen:useMobileDefaultSessionViewPreference:18:transport-error" + ], + "scenarioStatus": "planned-step1" + }, + { + "id": "pr19675:mobile/src/settings/native-notification-settings-operations.ts:preference:savePushNotificationsEnabled:18", + "file": "mobile/src/settings/native-notification-settings-operations.ts", + "symbol": "preference", + "line": 18, + "revision": "dc423947f48c9a0f694f48995aae5dcf817b1e35", + "method": "savePushNotificationsEnabled", + "kind": "device-preference", + "options": [], + "arguments": ["enabled"], + "consumedFields": [], + "writes": ["savePushNotificationsEnabled(enabled)"], + "failures": [], + "evidenceScope": "enclosing function; conservative source expressions, not a validated reader contract", + "scenarioIds": [ + "pr19675:mobile/src/settings/native-notification-settings-operations.ts:preference:savePushNotificationsEnabled:18:fulfilled", + "pr19675:mobile/src/settings/native-notification-settings-operations.ts:preference:savePushNotificationsEnabled:18:refused", + "pr19675:mobile/src/settings/native-notification-settings-operations.ts:preference:savePushNotificationsEnabled:18:transport-error" + ], + "scenarioStatus": "planned-step1" + }, + { + "id": "pr19675:mobile/src/settings/native-notification-settings-operations.ts:preference:loadPushNotificationsEnabled:20", + "file": "mobile/src/settings/native-notification-settings-operations.ts", + "symbol": "preference", + "line": 20, + "revision": "dc423947f48c9a0f694f48995aae5dcf817b1e35", + "method": "loadPushNotificationsEnabled", + "kind": "device-preference", + "options": [], + "arguments": [], + "consumedFields": [], + "writes": ["savePushNotificationsEnabled(enabled)"], + "failures": [], + "evidenceScope": "enclosing function; conservative source expressions, not a validated reader contract", + "scenarioIds": [ + "pr19675:mobile/src/settings/native-notification-settings-operations.ts:preference:loadPushNotificationsEnabled:20:fulfilled", + "pr19675:mobile/src/settings/native-notification-settings-operations.ts:preference:loadPushNotificationsEnabled:20:refused", + "pr19675:mobile/src/settings/native-notification-settings-operations.ts:preference:loadPushNotificationsEnabled:20:transport-error" + ], + "scenarioStatus": "planned-step1" + }, + { + "id": "pr19675:mobile/src/session/use-mobile-default-session-view-preference.ts:useMobileDefaultSessionViewPreference:loadDefaultSessionView().then:24", + "file": "mobile/src/session/use-mobile-default-session-view-preference.ts", + "symbol": "useMobileDefaultSessionViewPreference", + "line": 24, + "revision": "dc423947f48c9a0f694f48995aae5dcf817b1e35", + "method": "loadDefaultSessionView().then", + "kind": "device-preference", + "options": [], + "arguments": [ + "(view) => {\n // Why: a fast toggle is authoritative over the older storage read.\n if (!stale && mutationRevisionRef.current === loadRevision) {\n setDefaultViewState(view)\n }\n }" + ], + "consumedFields": [ + "loadDefaultSessionView().then", + "mountedRef.current", + "mutationRevisionRef.current" + ], + "writes": ["setDefaultViewState(view)"], + "failures": [], + "evidenceScope": "enclosing function; conservative source expressions, not a validated reader contract", + "scenarioIds": [ + "pr19675:mobile/src/session/use-mobile-default-session-view-preference.ts:useMobileDefaultSessionViewPreference:loadDefaultSessionView().then:24:fulfilled", + "pr19675:mobile/src/session/use-mobile-default-session-view-preference.ts:useMobileDefaultSessionViewPreference:loadDefaultSessionView().then:24:refused", + "pr19675:mobile/src/session/use-mobile-default-session-view-preference.ts:useMobileDefaultSessionViewPreference:loadDefaultSessionView().then:24:transport-error" + ], + "scenarioStatus": "planned-step1" + }, + { + "id": "pr19675:mobile/src/session/use-mobile-default-session-view-preference.ts:useMobileDefaultSessionViewPreference:loadDefaultSessionView:24", + "file": "mobile/src/session/use-mobile-default-session-view-preference.ts", + "symbol": "useMobileDefaultSessionViewPreference", + "line": 24, + "revision": "dc423947f48c9a0f694f48995aae5dcf817b1e35", + "method": "loadDefaultSessionView", + "kind": "device-preference", + "options": [], + "arguments": [], + "consumedFields": [ + "loadDefaultSessionView().then", + "mountedRef.current", + "mutationRevisionRef.current" + ], + "writes": ["setDefaultViewState(view)"], + "failures": [], + "evidenceScope": "enclosing function; conservative source expressions, not a validated reader contract", + "scenarioIds": [ + "pr19675:mobile/src/session/use-mobile-default-session-view-preference.ts:useMobileDefaultSessionViewPreference:loadDefaultSessionView:24:fulfilled", + "pr19675:mobile/src/session/use-mobile-default-session-view-preference.ts:useMobileDefaultSessionViewPreference:loadDefaultSessionView:24:refused", + "pr19675:mobile/src/session/use-mobile-default-session-view-preference.ts:useMobileDefaultSessionViewPreference:loadDefaultSessionView:24:transport-error" + ], + "scenarioStatus": "planned-step1" + }, + { + "id": "pr19675:mobile/src/session/use-mobile-default-session-view-preference.ts:setDefaultView:saveDefaultSessionView(view).catch:42", + "file": "mobile/src/session/use-mobile-default-session-view-preference.ts", + "symbol": "setDefaultView", + "line": 42, + "revision": "dc423947f48c9a0f694f48995aae5dcf817b1e35", + "method": "saveDefaultSessionView(view).catch", + "kind": "device-preference", + "options": [], + "arguments": [ + "async () => {\n const persisted = await loadDefaultSessionView()\n if (mountedRef.current && mutationRevisionRef.current === revision) {\n setDefaultViewState(persisted)\n }\n }" + ], + "consumedFields": [ + "mountedRef.current", + "mutationRevisionRef.current", + "saveDefaultSessionView(view).catch" + ], + "writes": [ + "saveDefaultSessionView(view)", + "saveDefaultSessionView(view).catch(async () => {\n const persisted = await loadDefaultSessionView()\n if (mountedRef.current && mutationRevisionRef.current === revision) {\n setDefaultViewState(persisted)\n }\n })", + "setDefaultViewState(persisted)", + "setDefaultViewState(view)" + ], + "failures": [], + "evidenceScope": "enclosing function; conservative source expressions, not a validated reader contract", + "scenarioIds": [ + "pr19675:mobile/src/session/use-mobile-default-session-view-preference.ts:setDefaultView:saveDefaultSessionView(view).catch:42:fulfilled", + "pr19675:mobile/src/session/use-mobile-default-session-view-preference.ts:setDefaultView:saveDefaultSessionView(view).catch:42:refused", + "pr19675:mobile/src/session/use-mobile-default-session-view-preference.ts:setDefaultView:saveDefaultSessionView(view).catch:42:transport-error" + ], + "scenarioStatus": "planned-step1" + }, + { + "id": "pr19675:mobile/src/session/use-mobile-default-session-view-preference.ts:setDefaultView:saveDefaultSessionView:42", + "file": "mobile/src/session/use-mobile-default-session-view-preference.ts", + "symbol": "setDefaultView", + "line": 42, + "revision": "dc423947f48c9a0f694f48995aae5dcf817b1e35", + "method": "saveDefaultSessionView", + "kind": "device-preference", + "options": [], + "arguments": ["view"], + "consumedFields": [ + "mountedRef.current", + "mutationRevisionRef.current", + "saveDefaultSessionView(view).catch" + ], + "writes": [ + "saveDefaultSessionView(view)", + "saveDefaultSessionView(view).catch(async () => {\n const persisted = await loadDefaultSessionView()\n if (mountedRef.current && mutationRevisionRef.current === revision) {\n setDefaultViewState(persisted)\n }\n })", + "setDefaultViewState(persisted)", + "setDefaultViewState(view)" + ], + "failures": [], + "evidenceScope": "enclosing function; conservative source expressions, not a validated reader contract", + "scenarioIds": [ + "pr19675:mobile/src/session/use-mobile-default-session-view-preference.ts:setDefaultView:saveDefaultSessionView:42:fulfilled", + "pr19675:mobile/src/session/use-mobile-default-session-view-preference.ts:setDefaultView:saveDefaultSessionView:42:refused", + "pr19675:mobile/src/session/use-mobile-default-session-view-preference.ts:setDefaultView:saveDefaultSessionView:42:transport-error" + ], + "scenarioStatus": "planned-step1" + }, + { + "id": "pr19675:mobile/src/session/use-mobile-default-session-view-preference.ts:setDefaultView:loadDefaultSessionView:43", + "file": "mobile/src/session/use-mobile-default-session-view-preference.ts", + "symbol": "setDefaultView", + "line": 43, + "revision": "dc423947f48c9a0f694f48995aae5dcf817b1e35", + "method": "loadDefaultSessionView", + "kind": "device-preference", + "options": [], + "arguments": [], + "consumedFields": ["mountedRef.current", "mutationRevisionRef.current"], + "writes": ["setDefaultViewState(persisted)"], + "failures": [], + "evidenceScope": "enclosing function; conservative source expressions, not a validated reader contract", + "scenarioIds": [ + "pr19675:mobile/src/session/use-mobile-default-session-view-preference.ts:setDefaultView:loadDefaultSessionView:43:fulfilled", + "pr19675:mobile/src/session/use-mobile-default-session-view-preference.ts:setDefaultView:loadDefaultSessionView:43:refused", + "pr19675:mobile/src/session/use-mobile-default-session-view-preference.ts:setDefaultView:loadDefaultSessionView:43:transport-error" + ], + "scenarioStatus": "planned-step1" + } + ] +} diff --git a/mobile/scripts/rpc-artifact-io.mts b/mobile/scripts/rpc-artifact-io.mts new file mode 100644 index 00000000000..b22125486ef --- /dev/null +++ b/mobile/scripts/rpc-artifact-io.mts @@ -0,0 +1,38 @@ +import { mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs' +import { dirname, join, relative, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' +import { isDeepStrictEqual } from 'node:util' +import { runProcess } from '../../src/shared/child-process/run-process.ts' +export const root = resolve(dirname(fileURLToPath(import.meta.url)), '../..') +export function files(directory: string): string[] { + return readdirSync(directory, { withFileTypes: true }) + .flatMap((entry) => { + const path = join(directory, entry.name) + return entry.isDirectory() ? files(path) : [relative(root, path).split('\\').join('/')] + }) + .sort() +} +export function option(name: string, fallback?: string): string { + const index = process.argv.indexOf(`--${name}`) + const value = index < 0 ? fallback : process.argv[index + 1] + if (!value || value.startsWith('--')) throw new Error(`Missing --${name}`) + return value +} +export async function git(...args: string[]): Promise { + const result = await runProcess({ program: 'git', args, cwd: root, maxOutputBytes: 8_000_000 }) + if (result.code !== 0 || result.outputTruncated) + throw new Error(`git ${args.join(' ')}: ${result.stderr}`) + return result.stdout.trimEnd() +} +export function emit(name: string, value: unknown): void { + const path = resolve(root, option('output', `mobile/rpc-foundation/${name}.json`)) + if (process.argv.includes('--check')) { + if (!isDeepStrictEqual(JSON.parse(readFileSync(path, 'utf8')), value)) + throw new Error(`Stale artifact: ${path}`) + console.log(`${name}: current`) + } else { + mkdirSync(dirname(path), { recursive: true }) + writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`) + console.log(`${name}: ${path}`) + } +} diff --git a/mobile/scripts/rpc-slice-manifest.mts b/mobile/scripts/rpc-slice-manifest.mts new file mode 100644 index 00000000000..c26069d8871 --- /dev/null +++ b/mobile/scripts/rpc-slice-manifest.mts @@ -0,0 +1,142 @@ +import { readFileSync } from 'node:fs' +import { dirname, join, posix } from 'node:path' +import { createHash } from 'node:crypto' +import ts from 'typescript' +import { emit, files, git, option, root } from './rpc-artifact-io.mts' + +const prHead = await git('rev-parse', `${option('pr-head')}^{commit}`) +const baseline = await git('rev-parse', 'e80fae0c4d^{commit}') +const diff = await git('diff', '--name-only', baseline, prHead, '--', 'mobile') +const changed = diff.split('\n').filter((file) => /\.[jt]sx?$/.test(file) && !/\.test\./.test(file)) +const hash = (text: string): string => createHash('sha256').update(text).digest('hex') +const rows: unknown[] = [] +const sources: { file: string; revision: string; sha256: string }[] = [] +function inventory(file: string, source: string, revision: string, settingsOnly: boolean): void { + const sf = ts.createSourceFile(file, source, ts.ScriptTarget.Latest, true) + let included = false + const visit = (node: ts.Node): void => { + if (ts.isCallExpression(node)) { + const literal = node.arguments.find( + (arg) => ts.isStringLiteral(arg) && /^(settings\.|dictation\.)/.test(arg.text) + ) + const callee = node.expression.getText(sf) + const preference = + /(?:load|save|set|use)\w*(?:Preference|LinkOpenMode|NotificationsEnabled|DefaultSessionView)/.test( + callee + ) + if (literal || (!settingsOnly && preference)) { + let owner: ts.Node = node + while ( + owner.parent && + !ts.isFunctionDeclaration(owner) && + !ts.isArrowFunction(owner) && + !ts.isMethodDeclaration(owner) + ) + owner = owner.parent + let named = owner + while (named.parent && !('name' in named && named.name)) named = named.parent + const symbol = + 'name' in named && named.name ? (named.name as ts.Node).getText(sf) : 'module' + const line = sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1 + const method = literal && ts.isStringLiteral(literal) ? literal.text : callee + const fields = new Set(), + writes = new Set(), + failures = new Set() + const evidence = (part: ts.Node): void => { + if (ts.isPropertyAccessExpression(part)) fields.add(part.getText(sf)) + if ( + ts.isCallExpression(part) && + /^(?:set|save|persist|dispatch|router\.)/.test(part.expression.getText(sf)) + ) + writes.add(part.getText(sf)) + if (ts.isThrowStatement(part) || ts.isCatchClause(part)) failures.add(part.getText(sf)) + if ( + ts.isBinaryExpression(part) && + [ts.SyntaxKind.BarBarToken, ts.SyntaxKind.QuestionQuestionToken].includes( + part.operatorToken.kind + ) + ) + failures.add(part.getText(sf)) + ts.forEachChild(part, evidence) + } + evidence(owner) + const id = `${revision === baseline ? 'main' : 'pr19675'}:${file}:${symbol}:${method}:${line}` + rows.push({ + id, + file, + symbol, + line, + revision, + method, + kind: literal ? 'host-rpc' : 'device-preference', + options: literal + ? node.arguments + .slice(node.arguments.indexOf(literal) + 2) + .map((arg) => arg.getText(sf)) + : [], + arguments: node.arguments.map((arg) => arg.getText(sf)), + consumedFields: [...fields].sort(), + writes: [...writes].sort(), + failures: [...failures].sort(), + evidenceScope: + 'enclosing function; conservative source expressions, not a validated reader contract', + scenarioIds: [`${id}:fulfilled`, `${id}:refused`, `${id}:transport-error`], + scenarioStatus: 'planned-step1' + }) + included = true + } + } + ts.forEachChild(node, visit) + } + visit(sf) + if (included) sources.push({ file, revision, sha256: hash(source) }) +} +for (const file of [...files(join(root, 'mobile/src')), ...files(join(root, 'mobile/app'))].filter( + (file) => /\.[jt]sx?$/.test(file) && !/\.test\.|\.generated\./.test(file) +)) { + const source = readFileSync(join(root, file), 'utf8') + if (/['"]settings\.(get|set)['"]/.test(source)) inventory(file, source, baseline, true) +} +const pending = changed.filter( + (file) => + file.startsWith('mobile/src/settings/') || + /^mobile\/app\/(?:.*settings|notifications)\.tsx$/.test(file) +) +const visited = new Set() +while (pending.length) { + const file = pending.shift()! + if (visited.has(file)) continue + visited.add(file) + const source = await git('show', `${prHead}:${file}`) + inventory(file, source, prHead, false) + const sf = ts.createSourceFile(file, source, ts.ScriptTarget.Latest, true) + for (const node of sf.statements) { + if (!ts.isImportDeclaration(node) || !ts.isStringLiteral(node.moduleSpecifier)) continue + const specifier = node.moduleSpecifier.text + if ( + !specifier.startsWith('.') || + !/(settings|dictation|preferences|default-session-view)/.test(specifier) + ) + continue + const base = posix.normalize(posix.join(dirname(file), specifier)) + for (const extension of ['.ts', '.tsx']) { + try { + await git('cat-file', '-e', `${prHead}:${base}${extension}`) + pending.push(`${base}${extension}`) + break + } catch { + /* Import resolution tries both source extensions. */ + } + } + } +} +if (!rows.length) throw new Error('Empty settings census') +emit('settings-19675', { + schemaVersion: 1, + prHead, + baseline, + diffSha256: hash(diff), + changedFiles: changed, + files: sources, + operations: rows +})