[#650][CODE] 云 web-search 闸改按真实引擎 id 命中 —— 空闸门 + 从未执行的契约校验 - #739
Open
jinjunnn wants to merge 2 commits into
Open
[#650][CODE] 云 web-search 闸改按真实引擎 id 命中 —— 空闸门 + 从未执行的契约校验#739jinjunnn wants to merge 2 commits into
jinjunnn wants to merge 2 commits into
Conversation
added 2 commits
July 31, 2026 07:47
引擎给远端 MCP 工具起名 = `McpCatalog.toolName(server, remote)` = `sanitize(server) + "_" + sanitize(remote)`。alpha 的 server 名是 `cloud`,而云 worker advertise 的远端名本身就叫 `cloud_web_search`(#643 P1.3 实测),真实引擎 id 因此是 `cloud_cloud_web_search`(P2.1 实测 `calledTool`)。仓里把这两层混为一谈, 后果两条: - kill-switch 下的 permission deny 写的是远端名,经 `Wildcard.match` 编成 `^cloud_web_search$`,对真实 id 恒不匹配 —— **空闸门**,云 web search 从未从 模型工具表里消失过; - ext 的云工具契约校验(`cloud-contract-hook.ts`)对四个兄弟工具用精确相等比远端名, `CloudJobRequestV1` / `CloudJobAcceptedV1` / `CloudJobStatusV1` / `ArtifactListV1` **一次也没执行过**。 AC4(kill-switch)未被击穿:ext 的 `tool.execute.before` 闸按工具形态判 (`isWebSearchToolId`),字面量无关,真实 id 照样命中。 id 一律推导:ui-mac `cloudMcpToolId()` / ext `mcpEngineToolId()` 与 `McpCatalog.toolName` 逐字同义。判据测试改用**真的** `McpCatalog` + 真的 `Permission.fromConfig`/`Permission.disabled` —— 手喂 id 的断言正是让这个缺陷 全绿活下来的原因。 Fixes #650 Refs #223
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #650
Refs #223
这修的是什么(大白话)
云端的 web search 工具有一道"总开关关掉时把它藏起来"的闸,和一道"云工具返回的数据必须符合契约"的检查。两道闸都在盯一个不存在的名字,所以从落地那天起一次也没生效过。
名字为什么错:引擎给远端 MCP 工具起名是
sanitize(server) + "_" + sanitize(远端名)(packages/opencode/src/mcp/catalog.ts:119)。alpha 的 server 叫cloud,而云 worker 自己 advertise 的工具名本来就叫cloud_web_search(#643 P1.3 实测)。两个一拼,引擎里的真实 id 是cloud_cloud_web_search(#643 P2.1 实测calledTool)。仓里把"远端名"和"引擎 id"当成了同一个东西。后果两条:
cloud_web_search,经Wildcard.match编成^cloud_web_search$,对真实 id 恒不匹配 ⇒ 云 web search 从来没有从模型工具表里消失过。本地跑真的Permission.fromConfig+Permission.disabled实测:旧键 → 隐藏集["websearch"](云工具不在内);新键 →["cloud_cloud_web_search"]。packages/ext/src/cloud-contract-hook.ts对cloud_dispatch/cloud_status/cloud_await/cloud_artifacts用精确相等比远端名,而钩子拿到的是引擎 id ⇒CloudJobRequestV1/CloudJobAcceptedV1/CloudJobStatusV1/ArtifactListV1一条也没跑过。#223 AC4(kill-switch)未被击穿:ext 的
tool.execute.before闸按工具形态判(isWebSearchToolId,刻意无字面量),真实 id 照样命中。被修的是可用性层与契约校验层。改法
id 一律推导,仓里不再有第二份字面量:
packages/ui-mac/src/main/cloud-web-search.ts— 拆出两层:CLOUD_WEB_SEARCH_REMOTE_TOOL(远端名)+cloudMcpToolId()(与McpCatalog.toolName逐字同义)⇒CLOUD_WEB_SEARCH_TOOL_ID由推导得出。packages/ext/src/cloud-websearch-kill.ts— 导出mcpEngineToolId(server, remote)(复用已有的sanitizeMcpName)。isWebSearchToolId一字未动(它是对的)。packages/ext/src/cloud-contract-hook.ts— 归属改为「本次 fork 的 server 名(ALPHA_CLOUD_MCP_SERVER,与治理豁免同源)+ 远端名」推导出的引擎 id。packages/core/src/tool/websearch.ts、packages/opencode/src/tool/mcp-websearch.ts,两者都在 north-star 守卫的 ADR-035 exclude 清单内)改成指向真实 id。判据(这次为什么不会再全绿)
原缺陷之所以活了一个需求,是因为所有相关测试都手喂 id:两边喂同一个错值,断言自然成立。现在:
packages/ui-mac/src/main/cloud-web-search.test.ts装的是真的McpCatalog与真的Permission.fromConfig/Permission.disabled,判据是引擎自己算出来的隐藏集,不是"config 里那个键等于某字符串"。McpCatalog.toolName(server, remote)。remoteWebSearchToolName/derivedEngineToolId—— 平台改名而仓里没跟上,下一次取证跑完就红。packages/ext/src/cloud-contract-hook.test.ts、packages/ui-mac/src/main/alpha-config-injection.test.ts、packages/opencode/test/tool/alpha-mcp-websearch-gate.test.ts里手喂的 id 全部改为推导(该套件里第三方那半场本来就是推导的,云那半场丢了这条纪律)。反向判据(真跑过,不是"应该会红")
CLOUD_WEB_SEARCH_TOOL_ID退回远端名"cloud_web_search"cloud-web-search.test.ts4 fail(含两条Permission.disabled行为断言)cloud-contract-hook.test.ts3 failcloud→alphacloudcloud-web-search+alpha-config-injection合计 7 failcloud_web_search→web_search本地门(真实输出)
bash scripts/alpha-check.sh→ALPHACHECK_EXIT=0bash scripts/assert-gate-files.sh→GATEFILES_EXIT=0,✓ 60 个闸门文件全部在位且真的跑过。与 base(
origin/alpha@7799a5e6,同一 worktree 同一命令)的差:packages/opencode/test/tool/alpha-mcp-websearch-gate.test.ts(不在 CI 范围,单跑)Bun.serve替身的用例 30s 超时 +ConnectionRefused localhost,与本改动无关的本机 flake)新增 fail:0。
文档影响
.claude/rules/adrs/ADR-009-websearch-default.md:裁决 (a) 里permission["cloud_web_search"] = "deny"是一条已成假的实现事实(正是缺陷来源),改成permission[CLOUD_WEB_SEARCH_TOOL_ID]并写明两层命名;后果段加一条✅ 已修 · #650,并把残留 (a) 的措辞改准(那里说的listTools列的确实是远端名)。已知边界(不谎称)
packages/opencode/src/mcp/catalog.ts的拼名规则(上游语义),也不改 ext 的isWebSearchToolId。packages/opencode/test/tool/alpha-mcp-websearch-gate.test.ts是 alpha 自有测试但住在 upstream 路径下。它不在scripts/gate-files.tsv,因此不被任何 CI 步骤执行 —— 本 PR 只把它里面手喂的 id 改成推导,没有把它注册进闸门登记簿(超出本票范围,见下方"主动没做")。--no-verify:钩子跑在共享主 checkout 上,而主 checkout 正被另一个 session(REQ-128)占用。等价的门已在本 worktree 真环境跑完,输出见上。