Fix App Server bridge read timeout classification

This commit is contained in:
coso
2026-08-11 08:03:49 +08:00
parent cd5bc4eae8
commit 8738c8a623
3 changed files with 44 additions and 187 deletions
+14 -1
View File
@@ -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 及判断 helpermethod 合法性继续由 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 保持不动。
+29 -16
View File
@@ -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: {
+1 -170
View File
@@ -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,