From e9f589c6ede333b1a9ab640f7bafdf129cbdfafa Mon Sep 17 00:00:00 2001 From: asto18089 Date: Mon, 14 Sep 2026 21:21:33 +0800 Subject: [PATCH 1/3] chore(baseline): resync the tui changelog slice, surface facts, and test clippy Split out of CodeWhale#56 per CONTRIBUTING.md: changelog entries are written on main at merge time and PRs carrying changelog hunks are asked to strip them, so the DDG-to-Bing degradation entry (behavior already merged in #44 via ff299f94b; the root CHANGELOG already carried it, the packaged tui slice did not) moves here together with its generated web twin. The surface-facts trio moves with it because no gate on the pinvou3-clean lane checks them; note v0.9.13 published on 2026-09-14, so the next receipts run should refresh latestPublishedRelease again. The redundant-closure cleanup in engine/tests.rs rides here because it blocks the master/main and release lint lanes, not the fork lane. Signed-off-by: asto18089 --- crates/tui/CHANGELOG.md | 12 ++++++++++++ crates/tui/src/core/engine/tests.rs | 2 +- docs/public-surface-facts.json | 8 ++++---- web/data/latest-published-release.json | 8 ++++---- web/lib/changelog.generated.ts | 10 +++++++++- web/lib/facts.generated.ts | 10 +++++----- 6 files changed, 35 insertions(+), 15 deletions(-) diff --git a/crates/tui/CHANGELOG.md b/crates/tui/CHANGELOG.md index 3be9d7ed7c..a607a79cda 100644 --- a/crates/tui/CHANGELOG.md +++ b/crates/tui/CHANGELOG.md @@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- API-backed `[search]` providers now visibly degrade directly to the + keyless Bing tail instead of routing through DuckDuckGo when + unavailable: DuckDuckGo is unreachable from mainland-China networks + (DNS poisoning plus SNI reset), while Bing serves its global and China + endpoints without a key. The all-backends-down guidance names every + keyed provider (tavily, bocha, metaso, baidu, volcengine, sofya) and + the keyless routes (firecrawl, bing), and the `web_search` tool + description no longer claims a DuckDuckGo hop for configured API + backends. + ## [0.9.12] - 2026-09-04 Codewhale v0.9.12 puts computer use in the binary, opens two new routes — diff --git a/crates/tui/src/core/engine/tests.rs b/crates/tui/src/core/engine/tests.rs index 91cc6c7354..91f29017e4 100644 --- a/crates/tui/src/core/engine/tests.rs +++ b/crates/tui/src/core/engine/tests.rs @@ -9803,7 +9803,7 @@ impl crate::core::model_client::ModelClient for CompleteOnceThenBlockModelClient canned::message_stop(), ]; return Ok(Box::pin(futures_util::stream::iter( - events.into_iter().map(|event| Ok(event)), + events.into_iter().map(Ok), ))); } let _drop_signal = DropSignal(std::sync::Arc::clone(&self.request_dropped)); diff --git a/docs/public-surface-facts.json b/docs/public-surface-facts.json index a3e9dbd955..4ee68884da 100644 --- a/docs/public-surface-facts.json +++ b/docs/public-surface-facts.json @@ -36,10 +36,10 @@ "providerCountDefinition": "Website-derived ApiProvider labels in this source snapshot, excluding Custom, DeepseekCN and retired Antigravity; includes protocol/plan variants. Not a count of distinct vendors, ProviderKind identities, live catalogs, or released v0.9.11 providers." }, "latestPublishedRelease": { - "tag": "v0.9.11", - "version": "0.9.11", - "publishedAt": "2026-08-23T17:39:46Z", - "url": "https://github.com/Hmbown/CodeWhale/releases/tag/v0.9.11", + "tag": "v0.9.12", + "version": "0.9.12", + "publishedAt": "2026-09-05T09:59:53Z", + "url": "https://github.com/Hmbown/CodeWhale/releases/tag/v0.9.12", "sources": [ "web/data/latest-published-release.json" ] diff --git a/web/data/latest-published-release.json b/web/data/latest-published-release.json index 2f876e3c54..ca65042725 100644 --- a/web/data/latest-published-release.json +++ b/web/data/latest-published-release.json @@ -1,6 +1,6 @@ { - "tag": "v0.9.11", - "version": "0.9.11", - "publishedAt": "2026-08-23T17:39:46Z", - "url": "https://github.com/Hmbown/CodeWhale/releases/tag/v0.9.11" + "tag": "v0.9.12", + "version": "0.9.12", + "publishedAt": "2026-09-05T09:59:53Z", + "url": "https://github.com/Hmbown/CodeWhale/releases/tag/v0.9.12" } diff --git a/web/lib/changelog.generated.ts b/web/lib/changelog.generated.ts index 6624c4cd4e..b3c07b470c 100644 --- a/web/lib/changelog.generated.ts +++ b/web/lib/changelog.generated.ts @@ -26,7 +26,15 @@ export const CHANGELOG: ChangelogRelease[] = [ "date": null, "unreleased": true, "compareUrl": "https://github.com/Hmbown/CodeWhale/compare/v0.9.12...HEAD", - "sections": [] + "sections": [ + { + "heading": "Fixed", + "items": [ + "API-backed [search] providers now visibly degrade directly to the keyless Bing tail instead of routing through DuckDuckGo when unavailable: DuckDuckGo is unreachable from mainland-China networks (DNS poisoning plus SNI reset), while Bing serves its global and China endpoints without a key. The all-backends-down guidance names every keyed provider (tavily, bocha, metaso, baidu, volcengine, sofya) and the keyless routes (firecrawl, bing), and the web_search tool description no…" + ], + "itemCount": 1 + } + ] }, { "version": "0.9.12", diff --git a/web/lib/facts.generated.ts b/web/lib/facts.generated.ts index e32d91f745..8a9ea2f017 100644 --- a/web/lib/facts.generated.ts +++ b/web/lib/facts.generated.ts @@ -27,7 +27,7 @@ export interface RepoFacts { } export const FACTS: RepoFacts = { - "generatedAt": "2026-09-03T18:51:05.927Z", + "generatedAt": "2026-09-14T03:09:31.167Z", "sourceRevision": null, "sourceCommittedAt": null, "version": "0.9.12", @@ -295,9 +295,9 @@ export const FACTS: RepoFacts = { "toolCount": 75, "license": "MIT", "latestPublishedRelease": { - "tag": "v0.9.11", - "version": "0.9.11", - "publishedAt": "2026-08-23T17:39:46Z", - "url": "https://github.com/Hmbown/CodeWhale/releases/tag/v0.9.11" + "tag": "v0.9.12", + "version": "0.9.12", + "publishedAt": "2026-09-05T09:59:53Z", + "url": "https://github.com/Hmbown/CodeWhale/releases/tag/v0.9.12" } }; From 2b1784c0e46079881a76b3b4714698701b48cc79 Mon Sep 17 00:00:00 2001 From: asto Date: Mon, 14 Sep 2026 23:21:29 +0800 Subject: [PATCH 2/3] fix(web): evolve telemetry trust prose with the release bump The surface-facts contract interpolated latestPublishedRelease.version into a required 'published release asked first' phrase. Once the pin moves to v0.9.12 that demanded phrase becomes false: 0.9.12 counts by default and never asked. Name the historically fixed asking release instead, matching the contract's upstream evolution: prose says 'earlier 0.9.11 release asked first' (en + zh), the test asserts it as a literal, and the roadmap/faq/telemetryLead copies follow. Catalogs regenerated with npm run i18n:gt -- export; npm test 407/407 green. Signed-off-by: asto --- docs/public-surface-facts.json | 2 +- web/app/[locale]/faq/page.tsx | 4 ++-- web/app/[locale]/roadmap/page.tsx | 4 ++-- web/gt-catalog/en.json | 2 +- web/gt-catalog/zh.json | 2 +- web/lib/i18n/dictionaries/en/docs-trust.ts | 2 +- web/lib/i18n/dictionaries/zh/docs-trust.ts | 2 +- web/lib/public-surface-contract.test.ts | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/public-surface-facts.json b/docs/public-surface-facts.json index 4ee68884da..ea5c7ad870 100644 --- a/docs/public-surface-facts.json +++ b/docs/public-surface-facts.json @@ -177,7 +177,7 @@ "localRuntime": "runtime, workspace state, and audit log stay on the user's machine", "hostedProviderBoundary": "the selected hosted provider receives turn context required for inference", "localInference": "a loopback local-model route can keep inference local", - "telemetry": "Codewhale 0.9.12 counts anonymous usage by default and discloses it at first launch (policy notice version 5, naming Codewhale and PostHog as processors), while the published 0.9.11 release asked first; turning it off is a saved choice that later versions keep, an opt-out recorded under the earlier opt-in policy stays off, and showing the notice never records any acceptance on the user's behalf; Codewhale does not collect conversations, code, prompts, files, file/repo/branch names, model content, credentials, or per-turn/per-tool timelines; while on, sessions post aggregate counts and closed enums to the first-party endpoint https://telemetry.codewhale.net/v1/telemetry, whose storage has no IP, country, or geo column and a fixed three-month retention; optional PostHog forwarding requires separate operator configuration and verified IP-safe egress, and its retention is a separate project setting; telemetry_endpoint = \"\" writes only to a local dry-run file; no mandatory hosted relay", + "telemetry": "Codewhale 0.9.12 counts anonymous usage by default and discloses it at first launch (policy notice version 5, naming Codewhale and PostHog as processors), while the earlier 0.9.11 release asked first; turning it off is a saved choice that later versions keep, an opt-out recorded under the earlier opt-in policy stays off, and showing the notice never records any acceptance on the user's behalf; Codewhale does not collect conversations, code, prompts, files, file/repo/branch names, model content, credentials, or per-turn/per-tool timelines; while on, sessions post aggregate counts and closed enums to the first-party endpoint https://telemetry.codewhale.net/v1/telemetry, whose storage has no IP, country, or geo column and a fixed three-month retention; optional PostHog forwarding requires separate operator configuration and verified IP-safe egress, and its retention is a separate project setting; telemetry_endpoint = \"\" writes only to a local dry-run file; no mandatory hosted relay", "account": "no account required for the local runtime", "plan": "Plan centrally refuses file mutation and shell execution; policy-allowed research may contact external services and local session state can still be persisted.", "sandbox": "Seatbelt is used on macOS when available; Linux bubblewrap is opt-in and must be installed; Windows currently reports no OS sandbox", diff --git a/web/app/[locale]/faq/page.tsx b/web/app/[locale]/faq/page.tsx index f0d553ff6b..10231ffe9a 100644 --- a/web/app/[locale]/faq/page.tsx +++ b/web/app/[locale]/faq/page.tsx @@ -229,7 +229,7 @@ codewhale --provider openrouter --model deepseek/deepseek-v4-pro <> The Codewhale runtime, workspace state, and audit log stay on your machine. Codewhale 0.9.12 counts anonymous usage by default and says so at first launch - (the published 0.9.11 release asked first). Turning it off is a saved choice that + (the earlier 0.9.11 release asked first). Turning it off is a saved choice that later versions keep, and an opt-out recorded under the earlier opt-in policy stays off; showing the notice never records any acceptance on your behalf. While on, a session posts aggregate session, feature, and error counts @@ -597,7 +597,7 @@ codewhale --provider openrouter --model deepseek/deepseek-v4-pro q: "我的代码安全吗?Codewhale 使用什么沙箱机制?", a: ( <> - Codewhale 运行时、工作区状态与审计日志保留在你的机器上。Codewhale 0.9.12 默认统计匿名使用量,并在首次启动时告知你(已发布的 0.9.11 版本会先询问)。 + Codewhale 运行时、工作区状态与审计日志保留在你的机器上。Codewhale 0.9.12 默认统计匿名使用量,并在首次启动时告知你(早先的 0.9.11 版本会先询问)。 关闭是会被后续版本保留的选择,在早先的自愿开启政策下记录的关闭也始终有效;显示告知绝不会代你记录任何同意。开启时,会话只会把聚合的会话、功能与错误计数以及封闭枚举 POST 到第一方端点{" "} https://telemetry.codewhale.net/v1/telemetry, 那是一个 Cloudflare Worker,完整源码就在仓库的 telemetry-ingest/ 目录里。 diff --git a/web/app/[locale]/roadmap/page.tsx b/web/app/[locale]/roadmap/page.tsx index 1e97fa1709..b55489e22c 100644 --- a/web/app/[locale]/roadmap/page.tsx +++ b/web/app/[locale]/roadmap/page.tsx @@ -34,7 +34,7 @@ const tracksEn = [ { title: "OpenAI-compatible & local runtimes", note: "Generic `openai` route for any OpenAI-compatible gateway, plus vLLM, SGLang, and Ollama against your own localhost endpoints — no key required" }, { title: "Multi-provider support", note: "Hot-swap between providers (DeepSeek, OpenAI, Anthropic, OpenRouter) per session" }, { title: "Local web client", note: "Implemented in the v0.9.1 source candidate: `codewhale web` is a loopback-only browser client over the Runtime API behind a one-time bootstrap session boundary; approvals and user input recover across page reloads (#4423)" }, - { title: "Anonymous usage counting", note: "On by default in Codewhale 0.9.12, disclosed at first launch; the published 0.9.11 release asked first. Turning it off is a saved choice that later versions keep, an opt-out recorded under the earlier opt-in policy stays off, and showing the notice never records any acceptance on your behalf. Codewhale and PostHog are the named processors. While on, sessions post aggregate session, feature, and error counts and closed enums to the first-party endpoint https://telemetry.codewhale.net/v1/telemetry, a Cloudflare Worker whose full source is in the repo under telemetry-ingest/. First-party storage has no IP, country, or geo column, records no request logs, and retains records for three months. Optional PostHog forwarding requires separate operator configuration and verified IP-safe egress; its retention is a separate project setting. Source support does not establish activation. Set telemetry_endpoint = \"\" to contact nobody: batches then go to $CODEWHALE_HOME/telemetry/dryrun.jsonl and you can read exactly what would have been sent. Never conversations, code, prompts, files, file/repo/branch names, model content, credentials, or a per-turn/per-tool timeline; the full schema is docs/TELEMETRY.md. Turn it off with `codewhale config set telemetry false` or CODEWHALE_TELEMETRY=0." }, + { title: "Anonymous usage counting", note: "On by default in Codewhale 0.9.12, disclosed at first launch; the earlier 0.9.11 release asked first. Turning it off is a saved choice that later versions keep, an opt-out recorded under the earlier opt-in policy stays off, and showing the notice never records any acceptance on your behalf. Codewhale and PostHog are the named processors. While on, sessions post aggregate session, feature, and error counts and closed enums to the first-party endpoint https://telemetry.codewhale.net/v1/telemetry, a Cloudflare Worker whose full source is in the repo under telemetry-ingest/. First-party storage has no IP, country, or geo column, records no request logs, and retains records for three months. Optional PostHog forwarding requires separate operator configuration and verified IP-safe egress; its retention is a separate project setting. Source support does not establish activation. Set telemetry_endpoint = \"\" to contact nobody: batches then go to $CODEWHALE_HOME/telemetry/dryrun.jsonl and you can read exactly what would have been sent. Never conversations, code, prompts, files, file/repo/branch names, model content, credentials, or a per-turn/per-tool timeline; the full schema is docs/TELEMETRY.md. Turn it off with `codewhale config set telemetry false` or CODEWHALE_TELEMETRY=0." }, ], }, { @@ -93,7 +93,7 @@ const tracksZh = [ { title: "OpenAI 兼容与本地运行时", note: "通用 `openai` 路由可接入任意 OpenAI 兼容网关;vLLM、SGLang、Ollama 直连本地端点,无需密钥" }, { title: "多提供商支持", note: "按会话动态切换提供商(DeepSeek、OpenAI、Anthropic、OpenRouter)" }, { title: "本地 Web 客户端", note: "v0.9.1 源码候选版已实现:`codewhale web` 是基于 Runtime API 与一次性引导会话边界的回环地址浏览器客户端;审批与用户输入可在页面刷新后恢复(#4423)" }, - { title: "匿名使用计数", note: "Codewhale 0.9.12 默认开启,并在首次启动时告知;已发布的 0.9.11 版本会先询问。关闭是会被后续版本保留的选择,在早先的自愿开启政策下记录的关闭也始终有效,显示告知绝不会代你记录任何同意。处理方为 Codewhale 和 PostHog。开启时,会话只会把聚合的会话、功能与错误计数以及封闭枚举 POST 到第一方端点 https://telemetry.codewhale.net/v1/telemetry;完整源码在 telemetry-ingest/。第一方存储没有 IP、国家或地理位置列,不记录请求日志,保留期固定为三个月。可选的 PostHog 转发需要运营方单独配置,并验证出口不会转发客户端 IP;其保留期由项目另行设置。源码支持不代表已启用。设置 telemetry_endpoint = \"\" 可完全不联系服务器,批次只写入 $CODEWHALE_HOME/telemetry/dryrun.jsonl。永远不收集对话、代码、prompt、文件、文件/仓库/分支名、模型内容、凭据,也不发送逐轮或逐工具时间线;完整 schema 见 docs/TELEMETRY.md。用 `codewhale config set telemetry false` 或 CODEWHALE_TELEMETRY=0 关闭。" }, + { title: "匿名使用计数", note: "Codewhale 0.9.12 默认开启,并在首次启动时告知;早先的 0.9.11 版本会先询问。关闭是会被后续版本保留的选择,在早先的自愿开启政策下记录的关闭也始终有效,显示告知绝不会代你记录任何同意。处理方为 Codewhale 和 PostHog。开启时,会话只会把聚合的会话、功能与错误计数以及封闭枚举 POST 到第一方端点 https://telemetry.codewhale.net/v1/telemetry;完整源码在 telemetry-ingest/。第一方存储没有 IP、国家或地理位置列,不记录请求日志,保留期固定为三个月。可选的 PostHog 转发需要运营方单独配置,并验证出口不会转发客户端 IP;其保留期由项目另行设置。源码支持不代表已启用。设置 telemetry_endpoint = \"\" 可完全不联系服务器,批次只写入 $CODEWHALE_HOME/telemetry/dryrun.jsonl。永远不收集对话、代码、prompt、文件、文件/仓库/分支名、模型内容、凭据,也不发送逐轮或逐工具时间线;完整 schema 见 docs/TELEMETRY.md。用 `codewhale config set telemetry false` 或 CODEWHALE_TELEMETRY=0 关闭。" }, ], }, { diff --git a/web/gt-catalog/en.json b/web/gt-catalog/en.json index a200650193..1af8e03354 100644 --- a/web/gt-catalog/en.json +++ b/web/gt-catalog/en.json @@ -751,7 +751,7 @@ ], "sandboxNote": "The repository also contains a seccomp module and a future Windows helper contract. Neither is wired into child-command launch, so Codewhale does not advertise them: source-only sandbox code is not evidence that a command was restricted.", "telemetryTitle": "Telemetry, exactly", - "telemetryLead": "Codewhale 0.9.12 counts anonymous usage by default and tells you so at first launch; the published 0.9.11 release asked first. Turning it off is a saved choice that later versions keep, and an opt-out recorded under the earlier opt-in policy stays off. Showing the notice never records any acceptance on your behalf; Codewhale and PostHog are named as the processors.", + "telemetryLead": "Codewhale 0.9.12 counts anonymous usage by default and tells you so at first launch; the earlier 0.9.11 release asked first. Turning it off is a saved choice that later versions keep, and an opt-out recorded under the earlier opt-in policy stays off. Showing the notice never records any acceptance on your behalf; Codewhale and PostHog are named as the processors.", "telemetry": [ [ "Never collected", diff --git a/web/gt-catalog/zh.json b/web/gt-catalog/zh.json index 9b8be2cc9d..c83c06d160 100644 --- a/web/gt-catalog/zh.json +++ b/web/gt-catalog/zh.json @@ -751,7 +751,7 @@ ], "sandboxNote": "仓库中还有一个 seccomp 模块和一份未来的 Windows 辅助程序契约。两者都没有接入子命令启动,所以 Codewhale 不会宣传它们:只存在于源码中的沙箱代码不能证明某条命令受到了限制。", "telemetryTitle": "遥测,精确到每一项", - "telemetryLead": "Codewhale 0.9.12 默认统计匿名使用量,并在首次启动时告知你;已发布的 0.9.11 版本会先询问。关闭是会被后续版本保留的选择,在早先的自愿开启政策下记录的关闭也始终有效。显示告知绝不会代你记录任何同意;处理方为 Codewhale 和 PostHog。", + "telemetryLead": "Codewhale 0.9.12 默认统计匿名使用量,并在首次启动时告知你;早先的 0.9.11 版本会先询问。关闭是会被后续版本保留的选择,在早先的自愿开启政策下记录的关闭也始终有效。显示告知绝不会代你记录任何同意;处理方为 Codewhale 和 PostHog。", "telemetry": [ [ "永远不收集", diff --git a/web/lib/i18n/dictionaries/en/docs-trust.ts b/web/lib/i18n/dictionaries/en/docs-trust.ts index a17aa3e934..493477b5fe 100644 --- a/web/lib/i18n/dictionaries/en/docs-trust.ts +++ b/web/lib/i18n/dictionaries/en/docs-trust.ts @@ -38,7 +38,7 @@ export const docsTrust: DocsTrustDict = { "The repository also contains a seccomp module and a future Windows helper contract. Neither is wired into child-command launch, so Codewhale does not advertise them: source-only sandbox code is not evidence that a command was restricted.", telemetryTitle: "Telemetry, exactly", telemetryLead: - "Codewhale 0.9.12 counts anonymous usage by default and tells you so at first launch; the published 0.9.11 release asked first. Turning it off is a saved choice that later versions keep, and an opt-out recorded under the earlier opt-in policy stays off. Showing the notice never records any acceptance on your behalf; Codewhale and PostHog are named as the processors.", + "Codewhale 0.9.12 counts anonymous usage by default and tells you so at first launch; the earlier 0.9.11 release asked first. Turning it off is a saved choice that later versions keep, and an opt-out recorded under the earlier opt-in policy stays off. Showing the notice never records any acceptance on your behalf; Codewhale and PostHog are named as the processors.", telemetry: [ ["Never collected", "Conversations, code, prompts, files, file/repo/branch names, model content, credentials, or any per-turn or per-tool timeline."], ["Sent while on", "Version and platform classes, session duration and outcome, feature and error counters, closed enums, and a random install id that rotates every 90 days."], diff --git a/web/lib/i18n/dictionaries/zh/docs-trust.ts b/web/lib/i18n/dictionaries/zh/docs-trust.ts index 0453c292e3..12212d6f19 100644 --- a/web/lib/i18n/dictionaries/zh/docs-trust.ts +++ b/web/lib/i18n/dictionaries/zh/docs-trust.ts @@ -36,7 +36,7 @@ export const docsTrust: DocsTrustDict = { sandboxNote: "仓库中还有一个 seccomp 模块和一份未来的 Windows 辅助程序契约。两者都没有接入子命令启动,所以 Codewhale 不会宣传它们:只存在于源码中的沙箱代码不能证明某条命令受到了限制。", telemetryTitle: "遥测,精确到每一项", - telemetryLead: "Codewhale 0.9.12 默认统计匿名使用量,并在首次启动时告知你;已发布的 0.9.11 版本会先询问。关闭是会被后续版本保留的选择,在早先的自愿开启政策下记录的关闭也始终有效。显示告知绝不会代你记录任何同意;处理方为 Codewhale 和 PostHog。", + telemetryLead: "Codewhale 0.9.12 默认统计匿名使用量,并在首次启动时告知你;早先的 0.9.11 版本会先询问。关闭是会被后续版本保留的选择,在早先的自愿开启政策下记录的关闭也始终有效。显示告知绝不会代你记录任何同意;处理方为 Codewhale 和 PostHog。", telemetry: [ ["永远不收集", "对话、代码、prompt、文件、文件/仓库/分支名、模型内容、凭据,以及任何逐轮或逐工具的时间线。"], ["开启时发送", "版本与平台类别、会话时长与结果、功能与错误计数、封闭枚举,以及一个每 90 天轮换的随机安装 id。"], diff --git a/web/lib/public-surface-contract.test.ts b/web/lib/public-surface-contract.test.ts index 314ea84b84..2a11d31992 100644 --- a/web/lib/public-surface-contract.test.ts +++ b/web/lib/public-surface-contract.test.ts @@ -503,7 +503,7 @@ done expect(matrix.trust.telemetry).toContain("discloses it at first launch"); expect(matrix.trust.telemetry).toContain("policy notice version 5"); expect(matrix.trust.telemetry).toContain("Codewhale and PostHog"); - expect(matrix.trust.telemetry).toContain(`published ${matrix.latestPublishedRelease.version} release asked first`); + expect(matrix.trust.telemetry).toContain("earlier 0.9.11 release asked first"); expect(matrix.trust.telemetry).toContain("never records any acceptance"); expect(matrix.trust.telemetry).toContain("opt-out recorded under the earlier opt-in policy stays off"); expect(matrix.trust.telemetry).not.toContain("requires explicit consent"); From ead3874ea0484fbce080e2282720fb5f6b0077ab Mon Sep 17 00:00:00 2001 From: asto18089 Date: Wed, 16 Sep 2026 23:44:10 +0800 Subject: [PATCH 3/3] test(web): anchor the asking-release phrase across site faces Review follow-up: the telemetry trust prose this PR evolves is mirrored across the en/zh dictionaries and the faq/roadmap pages with no test anchor, so a future edit could update one face and silently leave the others behind. Assert the fixed 'earlier 0.9.11 release asked first' phrasing (and its zh mirror) in every face and reject the interpolated 'published 0.9.11' wording; make providerCountDefinition version-free ('the providers of any published release') so the same stale-pin drift cannot recur there; refresh the stale comment above the telemetry assertions. Signed-off-by: asto18089 --- docs/public-surface-facts.json | 2 +- web/lib/public-surface-contract.test.ts | 30 ++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/docs/public-surface-facts.json b/docs/public-surface-facts.json index ea5c7ad870..4a846a2be2 100644 --- a/docs/public-surface-facts.json +++ b/docs/public-surface-facts.json @@ -33,7 +33,7 @@ "crates/tui/src/sandbox/mod.rs", "web/scripts/derive-facts.mjs" ], - "providerCountDefinition": "Website-derived ApiProvider labels in this source snapshot, excluding Custom, DeepseekCN and retired Antigravity; includes protocol/plan variants. Not a count of distinct vendors, ProviderKind identities, live catalogs, or released v0.9.11 providers." + "providerCountDefinition": "Website-derived ApiProvider labels in this source snapshot, excluding Custom, DeepseekCN and retired Antigravity; includes protocol/plan variants. Not a count of distinct vendors, ProviderKind identities, live catalogs, or the providers of any published release." }, "latestPublishedRelease": { "tag": "v0.9.12", diff --git a/web/lib/public-surface-contract.test.ts b/web/lib/public-surface-contract.test.ts index 2a11d31992..687ca25bf4 100644 --- a/web/lib/public-surface-contract.test.ts +++ b/web/lib/public-surface-contract.test.ts @@ -498,7 +498,7 @@ done expect(matrix.trust.localInference).toContain("loopback local-model route"); // The source candidate counts by default and says so. Disclosure alone // is never acceptance, every opt-out stays authoritative, and the - // published release's earlier opt-in behavior is named, not blurred. + // historically asking release (0.9.11) is named, not blurred. expect(matrix.trust.telemetry).toContain(`Codewhale ${matrix.sourceCandidate.version} counts anonymous usage by default`); expect(matrix.trust.telemetry).toContain("discloses it at first launch"); expect(matrix.trust.telemetry).toContain("policy notice version 5"); @@ -532,6 +532,34 @@ done expect(runtime).toContain("No hosted relay"); }); + it("names the asking release identically on every site face", () => { + // The asking-release reference names a historically fixed release, not + // the moving latestPublishedRelease pin: when the pin moved to 0.9.12 + // the interpolated "published release asked first" wording + // became a false claim. The same fixed phrasing is mirrored across the + // en/zh dictionaries and the faq/roadmap pages; anchor every copy so a + // future edit cannot update one face and silently leave the others + // describing a different contract. + const faq = text("web/app/[locale]/faq/page.tsx"); + const roadmap = text("web/app/[locale]/roadmap/page.tsx"); + for (const face of [ + text("web/lib/i18n/dictionaries/en/docs-trust.ts"), + faq, + roadmap, + ]) { + expect(face).toContain("earlier 0.9.11 release asked first"); + expect(face).not.toContain("published 0.9.11 release asked first"); + } + for (const face of [ + text("web/lib/i18n/dictionaries/zh/docs-trust.ts"), + faq, + roadmap, + ]) { + expect(face).toContain("早先的 0.9.11 版本会先询问"); + expect(face).not.toContain("已发布的 0.9.11 版本会先询问"); + } + }); + it("backs product vocabulary, contributor credit, and the exact MIT footer", () => { const fleet = text("docs/FLEET.md"); const changelog = text("CHANGELOG.md");