Skip to content

fix(websearch): 登录之后本地搜网仍留在模型工具表里 —— 账户信号只决定云腿在不在 - #1442

Merged
jinjunnn merged 1 commit into
alphafrom
feat/1411-local-websearch-stays-when-logged-in
Sep 24, 2026
Merged

jinjunnn merged 1 commit into
alphafrom
feat/1411-local-websearch-stays-when-logged-in

Conversation

@jinjunnn

Copy link
Copy Markdown
Owner

Fixes #1411
Refs #1414

owner 2026-09-23 裁决:本地和云端的搜网都必须有效,账户信号只决定「云腿在不在」,不决定「本地腿在不在」。 本地那条不花钱,是云腿 402 / 网络故障 / 平台故障时所有人的兜底,任何账户态都必须留着。

#1415(PR #1427,已合)已经让登出 / BYOK 态的本地 websearch 真的能出网。本 PR 只做剩下那一格:登录代付态下本地腿此前被主权闸有意关掉,并且还明确告诉模型「去用云端那个」。

方案基线:docs/design/2026-09-23-1414-web-tools-account-routing-baseline.md §二 / §七 CODE-1(owner 2026-09-24 批准)。


改了什么(生产面 4 个文件)

文件 改动
packages/ui-mac/src/main/server.ts applyWebSearchSovereignty() 不再读「平台代付」判据;连 userDataPath 形参一起去掉 —— 代付判据住在那底下的密钥文件里,参数没了就没人能顺手把它读回来。三个调用点同步更新,hasSecretFile 随之从该文件的 import 里消失。
packages/ui-mac/src/main/cloud-web-search.ts applyWebSearchDenies() 的本地腿 deny 只看 kill-switch;state.platformPays 在那一行刻意不被读。诊断串里的三元(kill switch / platform pays)收敛成固定的 kill switch —— kill-switch 态的输出逐字未变。
packages/core/src/tool/websearch.ts LOCAL_WEBSEARCH_DENIED_MESSAGE 改写。
packages/opencode/src/tool/mcp-websearch.ts 同上(packages/opencode/src/tool/websearch.ts 只是从这里转出,两个包之间没有可共用的依赖边,所以两份各写一份)。

云腿的任何一处、kill-switch 半场、出网围栏:一个字没改。

为什么文案必须跟着改(基线 S5)

改完之后 ALPHA_LOCAL_WEBSEARCH_DENY 只由 kill-switch 置位,而 kill-switch 同时关掉云腿。于是那句「Use cloud_cloud_web_search if it is present」在唯一还能到达它的状态下必然是错的 —— 它把模型指向一个同一时刻也不在工具表里的工具。新文案说 kill-switch 的实话,并明说没有替代;保留「do not retry」。

为什么 WebSearchSovereignty.platformPays 字段留着

它仍然是「云腿在不在」那一轴的真值,注入面在别处消费它(云 MCP 定义的形状)。更重要的是:cloud-web-search.test.ts 里 { killSwitch: false, platformPays: true } 那条臂正是钉住「代付一个 deny 都不产生」的反回归断言 —— 删掉字段就写不出那条断言。字段上写了一行注释说明它不得参与本地腿判定。


退出条件 ①:登录代付态下两个工具同时在模型工具表里

基线 §九 第 1 条把这件事标为「从代码结构推出来的推论,不是跑出来的」。本 PR 把它跑成事实。

新增 packages/ui-mac/src/main/server.test.ts 的一组用例,一条规则都不手写,四个供数方全是生产自己的:

  1. main 的 applyWebSearchSovereignty() + createSidecarEnv() 白名单 —— 经真 spawnLocalServer fork 出来的那份 env;
  2. 引擎的 RuntimeFlags(真 ConfigProvider 解析①给出的那份 env,不是手写 env[k] === "1");
  3. 引擎的 webSearchEnabled() —— 本地腿的注册闸(tool/registry.ts 的 tools() 用的就是它);
  4. 注入面的真 injectAlphaConfig() → 引擎的真 Permission.fromConfig + Permission.disabled —— 可见性闸(session/llm/request.ts 的 resolveTools() 用的就是它)。

实测输出(这条链在最终树上跑出来的真实工具表):

[EV] A 登出/BYOK        : ["websearch"]
[EV] B 登录代付          : ["websearch","cloud_cloud_web_search"]
[EV] C kill-switch+登录  : []
[EV] D kill-switch 关掉后: ["websearch","cloud_cloud_web_search"]
[EV] B 的 sidecar env    : {"OPENCODE_ENABLE_EXA":"1","ALPHA_CLOUD_MCP_URL":"https://cloud.example/mcp"}

(B 的 env 里 ALPHA_LOCAL_WEBSEARCH_DENY 与 ALPHA_CLOUD_WEBSEARCH_DENY 都不存在 —— 这正是本票要的。)

手段的自证(先证明它测得出已知的坏):C 那一格是反例臂,同一条链在 kill-switch 下两条腿一个都不在表里;它同时覆盖②(flag 被 force-off)与④(permission deny)。另外把生产代码改回旧语义跑了一次变异实验(applyWebSearchDenies 恢复 || state.platformPays,applyWebSearchSovereignty 恢复登录 force-off):四个测试文件 16 条当场转红,含上面这条端到端用例;还原后 67/67 回绿。

诚实边界,写在用例注释里:

  • 「登录+有额度」与「登录+无额度」在桌面侧不可区分(account 契约里没有只读额度查询,基线 §1.1(b)),两者在这里是同一格;「无额度」的可观察差别是云腿调用时的 402,不在本票范围。
  • 云腿「注册与否」的判据只保证代付且无 kill-switch这一格准确;kill-switch 下真定义经 ARM/DEF 交给 ext 的 installCloudMcp(),它读不到 {file:} 凭证时会响亮不装 —— 那半格一律按「已注册」处理,再由 permission deny 兜住,两条路径结论相同。

退出条件 ②:kill-switch 态的断言逐字未变

没有动过任何一条 kill-switch 断言。具体地:

  • cloud-web-search.test.ts 的 kill switch removes both web search tools…、kill-switch:引擎真的把云 web search 滤出模型工具表…、kill-switch:alpha 注入的 agent 也压得住… 三条断言体一字未动;
  • server.test.ts 的 disable overrides a shell-exported %s flag in every auth state、disable wins over all shell-exported keyless flags even when cloud is registered、the sovereignty verdict reaches the sidecar so the tool itself can refuse、turning the kill switch back off clears the cloud verdict on the next fork 一字未动;the kill switch ships a cloud verdict to the sidecar; platform-pays does not 只改了它的 platform-pays 那一行(ALPHA_LOCAL_WEBSEARCH_DENY 从 toBe("1") 变成 toBeUndefined()),kill-switch 那两行未动;
  • packages/ext 的 208 条(含 cloud-websearch-kill.test.ts 43 条)全绿且一字未改。
  • 生产侧:applyWebSearchDenies 在 kill-switch 态写出的两条诊断串与改前逐字节相同(三元收敛成的那个分支就是原来的 "kill switch")。

退出条件 ③:cloud-web-search.test.ts 的 platformPays 臂改成新语义 —— 为什么

原用例 原断言 现在 为什么必须改
platform pays denies the local websearch tool and leaves the cloud tool authoritative 代付 ⇒ permission.websearch === "deny" 改名为 platform pays denies nothing,断言 permission 与三个 agent 一个字都没被写、诊断为空 它断言的就是被 owner 推翻的那条规则。新形态是那条边被重新接上时当场翻红的反回归断言
no injected agent may re-allow a denied web search tool 三态循环,含 {killSwitch:false, platformPays:true} 去掉代付那一态(两个 kill-switch 态原样保留) 代付态现在没有被 deny 的 web search 工具,「不许 re-allow」对它无意义(空对空地绿)
an agent wildcard cannot re-allow a denied web search tool 驱动态是代付 驱动态换成 kill-switch,被测行为与断言体未变 唯一能产生 deny 的状态变了;这条用例测的是「deny 必须钉到末位」,与账户态无关
代付但无 kill-switch:云工具是权威通道,引擎不许把它藏起来 Permission.disabled(...) == [websearch] == [],并补一条 agent 级的同判据 期望值直接编码了「代付 ⇒ 藏起本地腿」。判据仍是引擎自己的 Permission.fromConfig/disabled,期望值仍从远端名经 McpCatalog.toolName 推导
两份拒绝文案指向的是引擎真实 id 文案必须含 Use cloud_cloud_web_search if it is present 断言文案不含云工具的引擎 id 与远端名,仍含 do not retry / Answer without web search and say so / kill switch;并新增一条「两份副本逐字相同」的漂移锁 见上文 S5。顺带把判据从「读文件正文」换成「读导出的值」—— 正文匹配会被注释里的同形字样骗过去

基线漏掉的一格(如实登记)

基线 §1.1(d) 只点名了 cloud-web-search.test.ts 的 5 处,并写「子票要改的就是它们,不是别的」。实测另有 3 个文件 10 条同样转红,全部是同一条边的落点:

  • packages/ui-mac/src/main/server.test.ts 8 条(#621 组 6 条 + #223 Major 3 组 2 条)
  • packages/ui-mac/src/main/alpha-config-injection.test.ts 1 条(真实生产 composition 下的代付臂)
  • packages/ui-mac/src/main/config-injection-throat.test.ts 1 条(代付态顶层 permission 键整个不再写出 ⇒ 「九个顶层键」变八个)

处置:凡「被测机制没变、只是唯一能驱动它的开关从登录换成 kill-switch」的,一律保留断言体、只换驱动态(并在注释里写明换了什么、以前是什么)。websearch-copies.test.ts 如基线所料没有变红(12/12),它查的是副本集合,不是选路。


本机门的真实输出

分支已 rebase 到 origin/alpha(基线随 #1413 / #1412 / #1424 / #1430 前移;git merge-tree 无冲突,rebase 后 typecheck 与全量单测都重跑过 —— 上游动过 alpha-config-injection.ts 并新增了第四个 alpha agent alpha-ask,它自带 websearch: "allow",与本票的逐 agent 压平兼容)。

步 命令 结果
[1/14] north-star bash scripts/north-star-guard.sh rc=0 · ✓ zero upstream package edits
[4/14] typecheck bun run typecheck rc=0 · 33/33 tasks
[5/14] contracts vendor bun run --cwd packages/alpha-contracts-consumer check:vendor rc=0 · 40 artifacts verified
[5/14] contracts 地板 bash scripts/bun-test-floor.sh 15 packages/alpha-contracts-consumer rc=0 · 60 条(下界 15)
[5/14] ext 地板 bash scripts/bun-test-floor.sh 100 packages/ext rc=0 · 208 条(下界 100)
[5/14] ui-mac 全量 + 棘轮 ALPHA_KNOWN_FAILS_FILE=scripts/known-fails.tsv bash scripts/bun-test-floor.sh 3000 packages/ui-mac src rc=0 · 5362 pass / 0 fail(385 files, 308s)
[5/14] app 滚动 pin bash scripts/bun-test-app.sh rc=0 · 5 个 alpha 判据文件 56 条逐文件精确匹配
[6/14] 闸门登记簿 bash scripts/assert-gate-files.sh rc=0 · 221 个闸门文件全部在位且条数与登记精确一致
[7/14] seed assets bash scripts/assert-seed-assets.sh rc=0
[8/14] docs gate 改动的 Markdown 枚举 空 ⇒ no-op(本 PR 零 Markdown 改动)
[14/14] 模块体积棘轮 bash scripts/assert-module-size.sh 三行全部 = 基线(planner 3539、ext-transaction 2825、src/main 59762);阈值那一半也无点名
定点复验 packages/core test/alpha-websearch-sovereignty.test.ts 11/11
定点复验 packages/opencode test/tool/{alpha-websearch-failure,alpha-mcp-websearch-gate}.test.ts 52/52
整条 pre-push 闸 git push(未用 --no-verify) PUSH_RC=0 · local gates passed;git ls-remote 读回 sha 与本地 HEAD 相同

与 base fail-set 的差:0 条新增红。 本次全量是 0 fail,所以「新增红」这一集合是空的,不依赖任何归因。pass 数的差是 +4(orchestrator 交的 base fail-set 是 rebase 前 8c8867c90 上的 5321 pass / 0 fail;rebase 带进来的三条上游 lane 补了其余):bun test src/main/server.test.ts --test-name-pattern "模型工具表" ⇒ 4 pass / 0 fail,正是本 PR 新增的那一组。

[9/14](worktree bootstrap 探针)[10/14](分支保护真源)[11/14](BYOK 目录)[13/14](漂移度量)在两次 push 里按脚本自己的三档语义各有「未验证 / 已测量」的自陈,与本 PR 改动无关;第一次 push 时 [14/14] 曾响过,处置见下。

手段自证(不是「跑过了都绿」)

  • north-star:先证明它测得出已知的坏 —— 往 packages/opencode/src/tool/registry.ts 提交一行(它在 ADR-041 收编白名单里)⇒ 仍 rc=0(正确);换成不在白名单的 packages/llm/src/index.ts ⇒ rc=1 并逐字点名该文件。两个探针提交都已 git reset --hard 掉。
  • 新用例:把生产代码改回旧语义(applyWebSearchDenies 恢复 || state.platformPays,applyWebSearchSovereignty 恢复登录 force-off)⇒ 四个测试文件 16 条当场转红,含那条端到端工具表用例;还原后 67/67 回绿。
  • 环境:本 worktree 补齐了两个未追踪产物(electron/{dist,path.txt} 软链主 checkout、alpha_fence.node 在本树现编),所以 process-fence-apply.test.ts / network-egress-fence.test.ts 不是定点假红 —— base 与 after 的全量都是 0 fail。

[14/14] 模块体积棘轮:它第一次响了,处置写在这里

第一次 push 时 [14/14] 点名两行:ext-install-planner.ts 3539 > 基线 3525(我没碰过那个文件,git show 8c8867c90:… | wc -l = 3539,主干上就已超基线,后来由 #1430/#1434 在主干上补齐)、以及 packages/ui-mac/src/main 59091 > 基线 59075(+16 全是我的,注释行)。

处置选的是拆小而不是抬基线:把两处新注释压紧(每一条事实都留着,只是更短),src/main 回到 59075 = 基线。理由 —— 16 行散文不值得抬一条全仓共享的基线,而且那一行同期有别的 lane 也要改,抬它等于替他们制造冲突。rebase 之后主干已把 tree 基线抬到 59762,本 PR 的净行数为 0,三行全部 = 基线。


我主动没做的事

  1. ADR-009 的 supersede / 新 ADR(D1–D5) —— 基线 §七划给 CODE-3(#1432)。本 PR 不碰 .claude/rules/adrs/,docs gate 因此是 no-op。
  2. 系统提示与工具表的一致性(S4) —— 归 CODE-2(#1431)。顺带交一条勘破:alpha-config-injection.ts 的能力判据是 process.env.OPENCODE_ENABLE_EXA !== "0"(单 flag),而本地腿真正的注册闸是引擎的 enableExa = OPENCODE_EXPERIMENTAL || OPENCODE_ENABLE_EXA || OPENCODE_EXPERIMENTAL_EXA 加 enableParallel 的两 flag OR —— 两者在「用户显式 export OPENCODE_ENABLE_EXA=0 且 export 了另外三个之一」时分叉。既有缺陷,本 PR 既没引入也没修;在登录代付态它今天不会被用户看见(identity 的 websearch 能力是 keyless || cloud,云腿在场就为真),分叉只在登出 / BYOK 态可观察。
  3. 四种账户态的 runtime 取证 —— 归 VERIFY-1。基线 §七 记的前置缺口仍在:没有零余额的真账户,402 的实际 wire body 从未跑过。本 PR 的证据是本机真 fork + 真引擎函数,不是打包实例上的模型真调用。
  4. ext 那道第三方 web search 闸随之松了一格 —— 观察到,按边界没碰。
    packages/ext/src/cloud-websearch-kill.ts 的 webSearchToolDenial() 对非治理 server 的 web search 工具判 localWebSearchDenied(env) || cloudWebSearchDenied(env)。本 PR 之后 ALPHA_LOCAL_WEBSEARCH_DENY 只由 kill-switch 置位 ⇒ 登录态下用户自带的第三方 web search MCP(如 exa_web_search_exa)不再被拦。方向上与「两条腿都活着」一致(它同样 keyless、不花平台的钱),但它是 ADR-009 B1 的另一处落点,而基线 D1 只说了「本地腿」。建议 CODE-3 的新 ADR 显式登记。
    同一文件的拒绝理由串仍写「the platform pays for search, or the web search kill switch is set」——「the platform pays」那半句现在不可达。它在 kill-switch / 云腿半场,票面明令不碰。
  5. packages/ui-mac/src/main/network-egress-registry.ts 里 #1415 那段注释仍写「登出 / BYOK 态下 websearch 是广告给模型的」;现在它在所有非 kill-switch 态都广告给模型。纯注释事实过时,不影响行为(放行集合本来就无条件),未改。
  6. bun run lint 有 1 个 error(packages/web 的 Invalid tsconfig: Cannot find type definition file for 'bun')+ 9480 warnings,全是既有噪声、与本 PR 改动的文件无关;scripts/alpha-check.sh 不跑 lint,它不是合并闸。未修。
  7. packages/ui-mac/tsconfig.json 排除 *.test.ts ⇒ 本 PR 改的 6 个测试文件不过 typecheck。已用 grep + 实跑两条轴交叉验证,不靠编译器。

🤖 Generated with Claude Code

owner 2026-09-23 裁决推翻 ADR-009 B1「一登录就只走云端」:本地 keyless
websearch 不花钱,是云腿 402 / 网络故障时唯一的退路,任何账户态都必须留着。
账户信号(平台代付)从此只决定**云腿在不在**。

- `applyWebSearchSovereignty()` 不再读代付判据,连 `userDataPath` 参数一起去掉
  —— 代付判据住在那底下的密钥文件里,参数没了就没人能顺手读回来。
- `applyWebSearchDenies()` 的本地腿 deny 只看 kill-switch;`platformPays` 刻意
  不被读,并由一条反回归断言钉住「代付一个 deny 都不产生」。
- 两份 `LOCAL_WEBSEARCH_DENIED_MESSAGE` 改成说 kill-switch 的实话:那句话现在
  只在 kill-switch 下可达,而那一态云工具同样不在表里,原来的指路必然是错的。
- 新增四条用例把基线 §九 第 1 条的**推论**跑成事实:真 fork 的 env → 真
  `RuntimeFlags` → 真 `webSearchEnabled` → 真 `injectAlphaConfig` → 真
  `Permission.disabled`,登录代付态两条腿同时在表里;kill-switch 反例臂证明
  这套手段测得出已知的坏。

kill-switch 半场、云腿、出网围栏一个字未改。

Refs #1414

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jinjunnn
jinjunnn merged commit 9d54476 into alpha Sep 24, 2026
5 of 6 checks passed
jinjunnn pushed a commit that referenced this pull request Sep 24, 2026
模型开场时被告知「你有搜网这个能力」,而它手里到底有没有这个工具是另一套逻辑决定的。
`#1414` 勘破 §6 测出全仓有四处在判「能不能搜网」,其中 `buildAlphaCapabilities` 把结论
**直接写进系统提示**,而它读的是 `ALPHA_WEBSEARCH_DISABLE` + `OPENCODE_ENABLE_EXA`,
与真闸(`applyWebSearchDenies` 的 deny 判决 + 云 MCP 定义的形状)**不同源** —— 于是可以
「提示说有、工具表里其实没有」,模型要么去调一个不存在的工具,要么凭印象编答案。

- `alpha-identity.ts`:`buildAlphaCapabilities` 的入参从「env 派生的三个布尔」换成
  「两条腿各自的**工具表在场性**」。它不再自己判,只把在场性折成提示事实;本模块必须保持
  零 import(ext 的登记簿直接 import 它),所以判据只能住在调用点。
- `alpha-config-injection.ts`:调用点改成**消费真闸自己的判决** —— 拿一个空壳 config 让
  `applyWebSearchDenies` 用同一组入参判一次再读判决,不手抄它的条件。云腿在场性读新增的
  `cloudMcpEnabled`(与写 `config.mcp` 那个三分支同一组输入)。顺带把同一函数里 26 行外
  重算一遍的 `Boolean(process.env.ALPHA_WEBSEARCH_DISABLE)` 换成已有的 `killSwitch` 常量。
- 新增四格闸门 `websearch-prompt-tool-parity.test.ts`(基线 §三 S4 / ADR-046 不变量的执行者),
  登记进 `scripts/gate-files.tsv`(精确条数 10)。四格 = 登出/BYOK · 登录有额度 · 登录无额度 ·
  kill-switch;keyless flag 当自由变量跑两遍,所以本闸对 `#1411` 前后两种 base 都成立。
  代付态那一格按 ADR-046 的目标态钉死(`#1411`/PR `#1442` 已合:代付一个 local deny 都不产生
  ⇒ 两条腿同时在模型工具表里);撤掉 `#1411` 的变异实测让这一格当场两臂全红。

`caps.websearch` 的取值与改动前逐格相同(`!kill && (keyless || platformPays)`,可代数化简
验证),所以这是一次同源化重构,不改任何账户态下的用户可见行为。

Refs #1414

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jinjunnn pushed a commit that referenced this pull request Sep 24, 2026
模型开场时被告知「你有搜网这个能力」,而它手里到底有没有这个工具是另一套逻辑决定的。
`#1414` 勘破 §6 测出全仓有四处在判「能不能搜网」,其中 `buildAlphaCapabilities` 把结论
**直接写进系统提示**,而它读的是 `ALPHA_WEBSEARCH_DISABLE` + `OPENCODE_ENABLE_EXA`,
与真闸(`applyWebSearchDenies` 的 deny 判决 + 云 MCP 定义的形状)**不同源** —— 于是可以
「提示说有、工具表里其实没有」,模型要么去调一个不存在的工具,要么凭印象编答案。

- `alpha-identity.ts`:`buildAlphaCapabilities` 的入参从「env 派生的三个布尔」换成
  「两条腿各自的**工具表在场性**」。它不再自己判,只把在场性折成提示事实;本模块必须保持
  零 import(ext 的登记簿直接 import 它),所以判据只能住在调用点。
- `alpha-config-injection.ts`:调用点改成**消费真闸自己的判决** —— 拿一个空壳 config 让
  `applyWebSearchDenies` 用同一组入参判一次再读判决,不手抄它的条件。云腿在场性读新增的
  `cloudMcpEnabled`(与写 `config.mcp` 那个三分支同一组输入)。顺带把同一函数里 26 行外
  重算一遍的 `Boolean(process.env.ALPHA_WEBSEARCH_DISABLE)` 换成已有的 `killSwitch` 常量。
- 新增四格闸门 `websearch-prompt-tool-parity.test.ts`(基线 §三 S4 / ADR-046 不变量的执行者),
  登记进 `scripts/gate-files.tsv`(精确条数 10)。四格 = 登出/BYOK · 登录有额度 · 登录无额度 ·
  kill-switch;keyless flag 当自由变量跑两遍,所以本闸对 `#1411` 前后两种 base 都成立。
  代付态那一格按 ADR-046 的目标态钉死(`#1411`/PR `#1442` 已合:代付一个 local deny 都不产生
  ⇒ 两条腿同时在模型工具表里);撤掉 `#1411` 的变异实测让这一格当场两臂全红。

`caps.websearch` 的取值与改动前逐格相同(`!kill && (keyless || platformPays)`,可代数化简
验证),所以这是一次同源化重构,不改任何账户态下的用户可见行为。

Refs #1414

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jinjunnn added a commit that referenced this pull request Sep 24, 2026
* feat(#1431): 让系统提示里的「能搜网」消费真闸的判决,而不是自己再判一遍

模型开场时被告知「你有搜网这个能力」,而它手里到底有没有这个工具是另一套逻辑决定的。
`#1414` 勘破 §6 测出全仓有四处在判「能不能搜网」,其中 `buildAlphaCapabilities` 把结论
**直接写进系统提示**,而它读的是 `ALPHA_WEBSEARCH_DISABLE` + `OPENCODE_ENABLE_EXA`,
与真闸(`applyWebSearchDenies` 的 deny 判决 + 云 MCP 定义的形状)**不同源** —— 于是可以
「提示说有、工具表里其实没有」,模型要么去调一个不存在的工具,要么凭印象编答案。

- `alpha-identity.ts`:`buildAlphaCapabilities` 的入参从「env 派生的三个布尔」换成
  「两条腿各自的**工具表在场性**」。它不再自己判,只把在场性折成提示事实;本模块必须保持
  零 import(ext 的登记簿直接 import 它),所以判据只能住在调用点。
- `alpha-config-injection.ts`:调用点改成**消费真闸自己的判决** —— 拿一个空壳 config 让
  `applyWebSearchDenies` 用同一组入参判一次再读判决,不手抄它的条件。云腿在场性读新增的
  `cloudMcpEnabled`(与写 `config.mcp` 那个三分支同一组输入)。顺带把同一函数里 26 行外
  重算一遍的 `Boolean(process.env.ALPHA_WEBSEARCH_DISABLE)` 换成已有的 `killSwitch` 常量。
- 新增四格闸门 `websearch-prompt-tool-parity.test.ts`(基线 §三 S4 / ADR-046 不变量的执行者),
  登记进 `scripts/gate-files.tsv`(精确条数 10)。四格 = 登出/BYOK · 登录有额度 · 登录无额度 ·
  kill-switch;keyless flag 当自由变量跑两遍,所以本闸对 `#1411` 前后两种 base 都成立。
  代付态那一格按 ADR-046 的目标态钉死(`#1411`/PR `#1442` 已合:代付一个 local deny 都不产生
  ⇒ 两条腿同时在模型工具表里);撤掉 `#1411` 的变异实测让这一格当场两臂全红。

`caps.websearch` 的取值与改动前逐格相同(`!kill && (keyless || platformPays)`,可代数化简
验证),所以这是一次同源化重构,不改任何账户态下的用户可见行为。

Refs #1414

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* chore(#1431): 按棘轮指示人手抬 tree 基线到实测值(59813 → 59854)

`scripts/assert-module-size.sh` 量出本票让 packages/ui-mac/src/main 非测试源码 +41 行
(全部是说明注释;先把两处注释收紧过一轮,+53 → +41)。基线只能靠人手 diff 抬高,评审看得见。

起点 = 干净 origin/alpha@78e751461 实测 59813,零遗留 ⇒ 这 41 行全部是本票的。基线与别人的
理由整份取 alpha 那一份,只重放本票这一段。树下两条 file 行(ext-install-planner.ts /
ext-transaction.ts)本票一行未动、实测均 = 基线,所以按 `#1438` 新加的交叉判据只抬 tree 这一行
(该判据自己的闸 17 pass / 0 fail)。

Refs #1414

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: jinjunnn <slmbaovanetti99@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[REQ-1414][CODE-1] 让本地搜网在登录之后仍然留在模型工具表里

1 participant