From 8738c8a623a763c50267d208facb4667ca9736c6 Mon Sep 17 00:00:00 2001 From: coso Date: Tue, 11 Aug 2026 08:03:49 +0800 Subject: [PATCH] Fix App Server bridge read timeout classification --- internal/exec-plans/release-v1.125.0-plan.md | 15 +- src/lib/dev-bridge/commandPolicy.test.ts | 45 +++-- src/lib/dev-bridge/commandPolicy.ts | 171 +------------------ 3 files changed, 44 insertions(+), 187 deletions(-) diff --git a/internal/exec-plans/release-v1.125.0-plan.md b/internal/exec-plans/release-v1.125.0-plan.md index c3cd8afbb..9f98ec95a 100644 --- a/internal/exec-plans/release-v1.125.0-plan.md +++ b/internal/exec-plans/release-v1.125.0-plan.md @@ -1,6 +1,6 @@ # Lime v1.125.0 发布执行计划 -状态:release-git-confirmation-pending / windows-runner-pending +状态:windows-gate-b-timeout-fix-in-progress 日期:2026-08-09 目标版本:`1.125.0` 目标 tag:`v1.125.0` @@ -191,3 +191,16 @@ - 本地验证:`cargo test --manifest-path lime-rs/Cargo.toml -p app-server plugin_uninstall_invalidates_mcp_runtimes_before_removing_package` 通过;`npm run test:rust:related -- lime-rs/crates/app-server/src/runtime.rs lime-rs/crates/app-server/src/runtime/plugins.rs lime-rs/crates/app-server/src/runtime_backend/execution_backend.rs lime-rs/crates/app-server/src/runtime/tests/plugins.rs` 通过,`app-server` lib `1642 passed / 0 failed`;`cargo fmt --all -- --check` 与 `git diff --check` 通过。 - `npm run typecheck`、`npm run test:contracts`、`npm run verify:app-version`、`npm run verify:gui-smoke` 均通过。真实 macOS packaged Plugin Gate B 通过:`ok=true`、卸载/installed projection/history recovery 全部通过、MCP App resource/HTML `4/4`、provider request `2`、`productionMockFallbackHitCount=0`、`missingRequiredMethods=[]`。 - 当前状态:`fix-validated-locally / release-git-confirmation-pending / windows-runner-pending`;下一步获得危险 Git 写操作确认后提交并推送窄修复,以新完整 SHA 重跑 Windows runner,不移动已发布 `v1.125.0` tag。 + +## Windows runner `31422354829` + +状态:`bridge-timeout-fix-in-progress / windows-runner-pending` + +- 使用完整 SHA `cd5bc4eae8211a2f4bdc1a7843b310618df18dc4`;Windows Plugin path contract、sherpa runtime、Electron Windows x64 Squirrel package、N-1 installer download 与 installed Squirrel smoke 全部通过。上一轮 `os error 32` 未复现,但 Gate B 在 reload 后的 session hydration 阶段失败,尚未执行到卸载。 +- 失败 evidence 已证明首次 MCP App surface、`mcpServer/resource/read`、HTML load、reload 后 canonical MCP item/plugin/resource URI 均正确;直接错误是 `thread/items/list` 经 `app_server_handle_json_lines` 在 5000ms 内未返回,Renderer fail closed 后主内容与 App surface 消失。 +- 根因:`commandPolicy.ts` 用手工 `APP_SERVER_CURRENT_METHODS` 同步 JSON-RPC method,漏掉 `thread/items/list` 与 `thread/turns/list`,导致新 read method 退回普通 truth 命令的 5 秒超时。该集合是 App Server protocol 之外的重复事实源。 +- 修复:保留 `turn/start`、conversation import、startup、knowledge compile、long-running 与 provider network 专项 profile;专项匹配后,所有 `app_server_handle_json_lines` 统一使用 `app-server-read` 的 30 秒窗口。删除手工 current method catalog 及判断 helper;method 合法性继续由 App Server protocol/handler fail closed,不由 bridge timeout policy 承担。 +- 窄写集:`src/lib/dev-bridge/commandPolicy.ts`、`src/lib/dev-bridge/commandPolicy.test.ts` 与本计划;不触碰并发架构、命令文档、projection drift 和治理 fixture 改动。 +- 本地验证:commandPolicy Vitest `11 passed / 0 failed`;定向 ESLint、`npm run typecheck`、`npm run test:contracts`、`npm run verify:app-version`、`npm run verify:gui-smoke` 与 `git diff --check` 均通过。GUI evidence:`standalone-shell-01-20260810194309-62252`。 +- 本机真实 packaged Plugin Gate B 通过:summary `ok=true`、provider request `2`、provider final text、MCP App 首次/reload/cold restore、App Center 卸载、installed projection 清理、卸载后历史恢复全部通过,`productionMockFallbackHitCount=0`、`missingRequiredMethods=[]`。 +- 退出条件:定向回归覆盖 `thread/items/list`、`thread/turns/list` 和未来 App Server method 均归 `app-server-read`;typecheck、contracts、GUI smoke 与本机真实 Electron Plugin Gate B 通过;随后提交并推送新完整 SHA,重新跟踪 Windows Gate B 到卸载、installed projection 清理与历史恢复全部通过。`v1.125.0` tag 保持不动。 diff --git a/src/lib/dev-bridge/commandPolicy.test.ts b/src/lib/dev-bridge/commandPolicy.test.ts index 210b47747..5d54fcdac 100644 --- a/src/lib/dev-bridge/commandPolicy.test.ts +++ b/src/lib/dev-bridge/commandPolicy.test.ts @@ -440,6 +440,35 @@ describe("commandPolicy", () => { }, }), ).toBe("app-server-read"); + for (const method of [ + "thread/items/list", + "thread/turns/list", + "futureDomain/futureMethod", + ]) { + expect( + resolveDevBridgeCommandTimeoutProfile("app_server_handle_json_lines", { + request: { + lines: [JSON.stringify({ id: `read-${method}`, method, params: {} })], + }, + }), + ).toBe("app-server-read"); + } + for (const method of [ + "pluginLocalPackage/inspect", + "pluginLocalPackage/export", + "pluginInstalled/save", + "pluginUiRuntime/start", + ]) { + expect( + resolveDevBridgeCommandTimeoutProfile("app_server_handle_json_lines", { + request: { + lines: [ + JSON.stringify({ id: `retired-${method}`, method, params: {} }), + ], + }, + }), + ).toBe("app-server-read"); + } expect( resolveDevBridgeCommandTimeoutProfile("app_server_handle_json_lines", { request: { @@ -501,22 +530,6 @@ describe("commandPolicy", () => { }), ).toBe("app-server-read"); } - for (const method of [ - "pluginLocalPackage/inspect", - "pluginLocalPackage/export", - "pluginInstalled/save", - "pluginUiRuntime/start", - ]) { - expect( - resolveDevBridgeCommandTimeoutProfile("app_server_handle_json_lines", { - request: { - lines: [ - JSON.stringify({ id: `retired-${method}`, method, params: {} }), - ], - }, - }), - ).toBe("truth"); - } expect( resolveDevBridgeCommandTimeoutProfile("app_server_handle_json_lines", { request: { diff --git a/src/lib/dev-bridge/commandPolicy.ts b/src/lib/dev-bridge/commandPolicy.ts index b3417b6da..f0c5fac8f 100644 --- a/src/lib/dev-bridge/commandPolicy.ts +++ b/src/lib/dev-bridge/commandPolicy.ts @@ -99,163 +99,6 @@ const APP_SERVER_PROVIDER_NETWORK_METHODS = new Set([ "modelProvider/testChat", "modelProvider/fetchModels", ]); -const APP_SERVER_MODEL_CONTROL_METHODS = new Set([ - "modelProvider/list", - "modelProvider/catalog/list", - "modelProvider/read", - "modelProvider/create", - "modelProvider/update", - "modelProvider/delete", - "modelProvider/sortOrders/update", - "modelProviderConfig/export", - "modelProviderConfig/import", - ...APP_SERVER_PROVIDER_NETWORK_METHODS, - "modelProviderKey/create", - "modelProviderKey/update", - "modelProviderKey/delete", - "modelProviderUiState/read", - "modelProviderUiState/write", - "modelProviderAlias/read", - "modelProviderAlias/list", -]); -const APP_SERVER_CURRENT_METHODS = new Set([ - "capability/list", - "artifact/read", - "fs/readFile", - "fs/writeFile", - "fs/createDirectory", - "fs/getMetadata", - "fs/readDirectory", - "fs/remove", - "fs/copy", - "fs/watch", - "fs/unwatch", - "thread/start", - "thread/read", - "workflow/read", - "workflow/cancel", - "workflow/retry", - "workflow/respond", - "thread/settings/update", - "thread/archive", - "thread/unarchive", - "skills/list", - "skill/read", - "skillManagement/list", - "skillManagement/install", - "skillManagement/uninstall", - "skillRepository/list", - "skillRepository/save", - "skillRepository/delete", - "skillCache/refresh", - "skillInstalledDirectories/list", - "skillLocal/inspect", - "skillLocal/scaffold/create", - "skillLocal/import", - "skillRemote/inspect", - "workspaceSkillBindings/list", - "workspaceRegisteredSkills/list", - "plugin/list", - "plugin/search", - "plugin/read", - "plugin/install", - "plugin/uninstall", - "plugin/installed", - "plugin/enabled/set", - "knowledgePack/list", - "knowledgePack/read", - "knowledgePack/source/import", - "knowledgePack/compile", - "knowledgePack/default/set", - "knowledgePack/status/update", - "knowledgeContext/resolve", - "knowledgeContextRun/validate", - "automationScheduler/config/read", - "automationScheduler/config/update", - "automationScheduler/status", - "automationJob/list", - "automationJob/read", - "automationJob/create", - "automationJob/update", - "automationJob/delete", - "automationJob/runNow", - "automationJob/health", - "automationJob/runHistory", - "automationSchedule/preview", - "automationSchedule/validate", - "projectMemory/read", - "gatewayChannel/status", - "wechatChannel/accounts/list", - "mediaTaskArtifact/image/create", - "mediaTaskArtifact/audio/create", - "mediaTaskArtifact/image/complete", - "mediaTaskArtifact/audio/complete", - "mediaTaskArtifact/get", - "mediaTaskArtifact/list", - "mediaTaskArtifact/cancel", - "workspaceRightSurface/request", - "workspaceRightSurface/pending/list", - "workspaceRightSurface/pending/consume", - "workspaceRightSurface/pending/dismiss", - "sessionFile/getOrCreate", - "sessionFile/updateMeta", - "sessionFile/save", - "sessionFile/list", - "sessionFile/read", - "sessionFile/resolvePath", - "sessionFile/delete", - "collaborationMode/list", - "model/list", - "modelPreferences/list", - "modelSyncState/read", - ...APP_SERVER_MODEL_CONTROL_METHODS, - "mcpServer/list", - "mcpServerStatus/list", - "mcpServer/create", - "mcpServer/update", - "mcpServer/delete", - "mcpServer/enabled/set", - "mcpServer/importFromApp", - "mcpServer/syncAllToLive", - "mcpServer/oauth/login", - "mcpServer/start", - "mcpServer/stop", - "mcpServer/resource/read", - "mcpServer/tool/call", - "mcpTool/list", - "mcpTool/listForContext", - "mcpTool/search", - "mcpPrompt/list", - "mcpPrompt/get", - "mcpResource/list", - "mcpResource/subscribe", - "mcpResource/unsubscribe", - "connectDeepLink/resolve", - "connectOpenDeepLink/resolve", - "voiceAsrCredential/list", - "voiceAsrCredential/create", - "voiceAsrCredential/update", - "voiceAsrCredential/delete", - "voiceAsrCredential/default/set", - "voiceAsrCredential/test", - "voiceInstruction/list", - "voiceInstruction/save", - "voiceInstruction/delete", - "voiceModel/default/set", - "voiceModel/testTranscribeFile", - "voiceTranscription/transcribeAudio", - "voiceTranscription/polishText", - "conversationImport/source/scan", - "conversationImport/job/read", - "conversationImport/thread/preview", - "conversationImport/thread/commit", - "projectGit/status", - "projectGit/diff", - "projectGit/commits/list", - "projectGit/branch/checkout", - "projectGit/branch/create", - "projectGit/worktree/create", -]); const APP_SERVER_STARTUP_TRUTH_METHODS = new Set([ "workspace/default/read", "workspace/default/ensure", @@ -351,7 +194,7 @@ export function resolveDevBridgeCommandTimeoutProfile( if (isAppServerProviderNetworkCommand(command, args)) { return "app-server-provider-network"; } - if (isAppServerCurrentMethodCommand(command, args)) { + if (command === APP_SERVER_HANDLE_JSON_LINES_COMMAND) { return "app-server-read"; } if (command === APP_SERVER_DRAIN_EVENTS_COMMAND) { @@ -435,18 +278,6 @@ function isAppServerLongRunningCommand( ); } -function isAppServerCurrentMethodCommand( - command: string, - args: unknown, -): boolean { - if (command !== APP_SERVER_HANDLE_JSON_LINES_COMMAND) { - return false; - } - return extractAppServerJsonLines(args).some((line) => - jsonRpcLineHasAnyMethod(line, APP_SERVER_CURRENT_METHODS), - ); -} - function isAppServerProviderNetworkCommand( command: string, args: unknown,