From db2ed089a378b2d8f6ecb07d39af9dd4a292acba Mon Sep 17 00:00:00 2001 From: chendelian <116870791@qq.com> Date: Sat, 12 Sep 2026 14:08:33 +0800 Subject: [PATCH] Release v1.0.108: precipitate user-facing copy contract --- CHANGELOG.md | 6 ++ SKILL.md | 3 +- assets/README.md | 2 +- assets/examples/README.md | 2 +- ...election-mode-optional.action.example.json | 8 +-- development/CHECKLIST.md | 3 +- development/SKILL_ACTION_RUNTIME.md | 4 +- references/ACTIONS.md | 41 ++++++++++++++ scripts/util/constants.py | 2 +- tests/test_actions_manifest.py | 55 +++++++++++++++++++ tests/test_docs_standards.py | 6 ++ 11 files changed, 121 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 453c264..67ab396 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ - 小节正文写用户能看懂的变化(新能力、修复、注意事项),避免堆砌内部实现细节 - 打 tag 前**必须**为即将发布的版本新增一节;找不到匹配小节时,本次发布不会更新 changelog 字段 +## 1.0.108 + +- 沉淀数据管理「用户可见文案」契约:弹窗 description / 确认黄条 / 参数说明 / 任务失败 message 须全中文产品用语 +- 明确禁止把字段名、CLI 子命令、async/pending、Agent 禁令写进用户可见文案;Agent 路由仍放 SKILL.md +- 修正 `selection-mode-optional` 示例为口语文案;更新 ACTIONS / RUNTIME / CHECKLIST A4-10 + ## 1.0.107 - 沉淀数据管理 `bind.selectionMode` 契约(`required` / `none` / `optional`):同一按钮可「有勾选走 ids、无勾选走 pickCount」 diff --git a/SKILL.md b/SKILL.md index 67145ad..efc36b8 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,7 +1,7 @@ --- name: 技能开发模板(通用业务版) description: "OpenClaw 通用业务技能开发模板,供复制后定制新业务 skill。定制步骤见 development/DEVELOPMENT.md。" -version: 1.0.107 +version: 1.0.108 author: 深圳匠厂科技有限公司 metadata: openclaw: @@ -39,6 +39,7 @@ allowed-tools: - **`placements`**:只决定 Action **出现在哪里**(toolbar / row / batch / cron / agent / skill-detail)。其中 `row` 表示**行级入口**(宿主可呈现为操作列、行右键、行内「⋯」等;技能配什么就显示什么,无独立菜单 DSL)。数据管理技能按钮顺序见 `actions` **数组相对顺序**(详见 `references/ACTIONS.md`),无独立 sortOrder。 - **`bind.tables`**:只决定数据管理出现在哪些表;含 `toolbar` 时**必须**显式非空绑定。 - **`bind.selectionMode`(可选)**:表勾选如何驱动 Action(`required` / `none` / `optional`);省略由宿主推断。同一能力勿拆两个同义顶栏按钮,见 `references/ACTIONS.md`。 +- **用户可见文案**:数据管理弹窗 / 任务中心文案须全中文产品用语;勿把 `pickCount`、`async`、`pending`、CLI 子命令写进弹窗(见 `references/ACTIONS.md`「用户可见文案」)。 - **`executionProfile`**:只决定执行方式——`sync` 当场返回结果,`async` 进**任务中心**。与 placements / 入口**无关**。心智上多数为 sync,仅长任务 / RPA 标 async;宿主省略该字段时按 sync。每个 Action **仍必须**显式写 `sync` 或 `async`。 - **`policy`(可选)**:需要按用户/角色控制数据管理按钮或行列时,在 `actions.json` 顶层启用 Data Policy,由技能 `policy` CLI 输出 Snapshot;**未启用 = 与今日一致(L0)**。详见 `references/POLICY.md`。用户/角色数据源(飞书/库/API)属技能内部,宿主不托管。 - **`cellPresentation`(可选)**:需要数据管理「某格特殊标色/强调」时启用;技能按当前数据写入呈现(语义 tone),宿主映射主题样式;**未启用 = P0 无标色**。用途不限(超时、预警、驳回等)。详见 `references/CELL_PRESENTATION.md`。 diff --git a/assets/README.md b/assets/README.md index be818d7..654bf57 100644 --- a/assets/README.md +++ b/assets/README.md @@ -6,7 +6,7 @@ - `examples/`:CLI 成功输出形状示例、Action 形状参考(含 `path-root-file-action.example.json`、`selection-label-column.action.example.json`、`selection-mode-optional.action.example.json`、`render-html.action.example.json` 等;虚构路径与数据)。 - `schemas/`:轻量 JSON Schema(`skill-actions.schema.json` 为**新技能严格规范**)。 -`skill-actions.schema.json` 使用 `additionalProperties: false`。正式支持 `bind.tables`(toolbar Action 必填)与可选 `bind.inputMapping` / `columnMapping` / **`labelColumn`**(选择摘要标签列)/ **`selectionMode`**(`required` \| `none` \| `optional`:表勾选如何驱动 Action;省略则宿主兼容推断)。placements 含 `toolbar` / `row` / `batch` / `cron` / `agent` / `skill-detail`(对齐匠厂宿主)。数据管理 confirm/form 弹层在会应用勾选时展示「已选择」摘要;**form + 有摘要时映射 `readOnly` 默认不占参数区(仍提交)**,可选 **`revealInForm`** 强制显示。可选 `hoverHint` 为数据管理工具栏悬停(省略不显示,不回退)。`concurrency`/`locks` 仍为预留。`placements` 与 `executionProfile` 正交——进任务中心只看 `async`,与入口无关。表级 Action 与 Agent 契约见 [`references/ACTIONS.md`](../references/ACTIONS.md);开发深度规范见 [`development/SKILL_ACTION_RUNTIME.md`](../development/SKILL_ACTION_RUNTIME.md)。 +`skill-actions.schema.json` 使用 `additionalProperties: false`。正式支持 `bind.tables`(toolbar Action 必填)与可选 `bind.inputMapping` / `columnMapping` / **`labelColumn`**(选择摘要标签列)/ **`selectionMode`**(`required` \| `none` \| `optional`:表勾选如何驱动 Action;省略则宿主兼容推断)。placements 含 `toolbar` / `row` / `batch` / `cron` / `agent` / `skill-detail`(对齐匠厂宿主)。数据管理 confirm/form 弹层在会应用勾选时展示「已选择」摘要;**form + 有摘要时映射 `readOnly` 默认不占参数区(仍提交)**,可选 **`revealInForm`** 强制显示。弹窗 `description` / 确认黄条 / 参数说明须**用户可见中文**(勿写 `pickCount`/`async`/`pending`/CLI 子命令;见 ACTIONS.md「用户可见文案」)。可选 `hoverHint` 为数据管理工具栏悬停(省略不显示,不回退)。`concurrency`/`locks` 仍为预留。`placements` 与 `executionProfile` 正交——进任务中心只看 `async`,与入口无关。表级 Action 与 Agent 契约见 [`references/ACTIONS.md`](../references/ACTIONS.md);开发深度规范见 [`development/SKILL_ACTION_RUNTIME.md`](../development/SKILL_ACTION_RUNTIME.md)。 - 用户市场四 Tab 见根目录 [`README.md`](../README.md) / [`TUTORIAL.md`](../TUTORIAL.md) / [`DEMO.md`](../DEMO.md) / [`CHANGELOG.md`](../CHANGELOG.md);写法契约见 [`development/TUTORIAL_SURFACES.md`](../development/TUTORIAL_SURFACES.md) - Agent 调用/编排参考见 [`references/`](../references/)(含 [`ACTIONS.md`](../references/ACTIONS.md)) diff --git a/assets/examples/README.md b/assets/examples/README.md index 871ab93..4b68735 100644 --- a/assets/examples/README.md +++ b/assets/examples/README.md @@ -7,5 +7,5 @@ - `lookup-action.example.json`:Action 内联 Lookup 形状参考(单选 + `multiple: true` 多选并列;跨表引用勿填编号;见 `references/ACTIONS.md`「跨表引用:Lookup」)。 - `visible-when-action.example.json`:Action 参数字段条件显隐 `visibleWhen` 形状参考(互斥模式联动;见 `references/ACTIONS.md`「字段条件显隐」;≠ Policy L3)。 - `selection-label-column.action.example.json`:选择摘要 `bind.labelColumn` 形状参考(见 `references/ACTIONS.md`「选择摘要」)。 -- `selection-mode-optional.action.example.json`:`bind.selectionMode: "optional"` 智能勾选/按数量合并形状参考(见 `references/ACTIONS.md`「勾选驱动模式」)。 +- `selection-mode-optional.action.example.json`:`bind.selectionMode: "optional"` 智能勾选/按数量合并形状参考;用户可见文案为口语中文(见 `references/ACTIONS.md`「勾选驱动模式」「用户可见文案」)。 - `replaces-create.action.example.json` / `replaces-update.action.example.json` / `replaces-delete.action.example.json` / `replaces-import.action.example.json`:数据管理默认按钮接管(`replaces`)形状参考;**import 时 UI 仍用宿主「导入数据」面板**,确认后调技能写库(见 `references/ACTIONS.md`「`replaces`」)。 diff --git a/assets/examples/selection-mode-optional.action.example.json b/assets/examples/selection-mode-optional.action.example.json index 04e3843..cc349a6 100644 --- a/assets/examples/selection-mode-optional.action.example.json +++ b/assets/examples/selection-mode-optional.action.example.json @@ -1,12 +1,12 @@ { "id": "process-queue", "label": "处理队列", - "description": "有勾选则按编号处理;无勾选则按 pickCount 从可操作队列领取。示例:bind.selectionMode=optional,避免拆成两个同义顶栏按钮。", + "description": "从业务队列处理待处理记录。有勾选则处理勾选的;没有勾选则按下方数量从队列领取。已成功或失败的会自动跳过。进度可在任务中心查看。", "placements": ["toolbar", "batch", "cron", "agent"], "executionProfile": "async", "interaction": "form", "confirmation": { - "message": "将按技能业务规则处理记录(有勾选则处理勾选;未勾选则按数量从队列领取)。" + "message": "将按规则处理记录(有勾选则处理勾选的;未勾选则按数量从队列领取),是否继续?" }, "bind": { "tables": ["business_items"], @@ -23,13 +23,13 @@ "itemIds": { "type": "string", "title": "编号列表", - "description": "勾选时由宿主预填;无勾选时不要传", + "description": "有勾选时自动填入,一般无需修改", "readOnly": true }, "pickCount": { "type": "number", "title": "处理数量", - "description": "未勾选时:从队列领取可操作状态记录的条数", + "description": "没有勾选时:从待处理队列里领取的条数", "default": 1, "minimum": 1 } diff --git a/development/CHECKLIST.md b/development/CHECKLIST.md index cd4eae8..e74b386 100644 --- a/development/CHECKLIST.md +++ b/development/CHECKLIST.md @@ -112,6 +112,7 @@ checklist_version: 1.0 - [ ] A4-7 **P1** 若 Action 有互斥采集/操作模式(如「按关键词 / 按主页」):用 `inputSchema` 字段级 **`visibleWhen`** 联动显隐,勿只靠 `description` 灰字说明「仅某某时填写」(见 `references/ACTIONS.md`;勿与 Policy L3 行态 `visibleWhen` 混淆) - [ ] A4-8 **P1** 行内/勾选打开的 `form`:有「已选择」时参数区不应再重复映射主键(`inputMapping` + `readOnly`);需要强制露出时用 `revealInForm`,**禁止**用 `visibleWhen` 藏主键(会不提交) - [ ] A4-9 **P1** 若同一能力既支持「勾选处理」又支持「按数量从队列领取」:用一个 Action + `bind.selectionMode: "optional"`(勿拆两个同义顶栏按钮);无勾选可点、有勾选显示「已选择」、空选数量字段用 `pickCount` 等约定名(见 `references/ACTIONS.md`) +- [ ] A4-10 **P0** 数据管理弹窗与任务失败文案:全中文产品用语;禁止在 `description` / `confirmation.message` / 参数 `description` / 用户向 `message` 写英文字段名、CLI 子命令、`async`/`pending`/`status=` 等(Agent 路由放 `SKILL.md`;见 `references/ACTIONS.md`「用户可见文案」) --- ## 5. 账号与浏览器会话(网页 RPA 适用;其他形态标 N/A 或改测等价项) @@ -157,7 +158,7 @@ checklist_version: 1.0 - [ ] A7-3 **P0** 故意失败一条时,文件日志先有 `task_failed`/`warning`,再有 `ERROR:CODE` 或任务中心失败态 - [ ] A7-4 **P1** 关键步骤有据可查(能对应到开始/关键节点/结束;RPA 宜有多个 `stage=`) - [ ] A7-5 **P1** 若宣称支持录屏或截图存证:打开开关后关键步骤或失败能留下可查看产物;宣称支持却完全无产物 → **FAIL** -- [ ] A7-6 **P2** 用户可见文案偏业务语言,而非大段开发黑话 +- [ ] A7-6 **P2** 用户可见文案偏业务语言,而非大段开发黑话(数据管理弹窗 / 任务失败见 **A4-10**,更高优先级) - [ ] A7-7 **P2** 数据管理技能按钮(toolbar / row / batch)中文名对照 `references/ACTIONS.md`「Action 按钮中文名」;不与宿主「查看 / 编辑 / 删除」抢名;打开类成功不弹成功条。行业专有按钮名可自创 --- diff --git a/development/SKILL_ACTION_RUNTIME.md b/development/SKILL_ACTION_RUNTIME.md index 0ce68b0..c3dc643 100644 --- a/development/SKILL_ACTION_RUNTIME.md +++ b/development/SKILL_ACTION_RUNTIME.md @@ -9,7 +9,7 @@ | 文档 | 职责 | |------|------| | 本文 | sync/async、任务中心、Agent 禁令、单内核编排、队列 pick、同步 vs 导出 | -| [`../references/ACTIONS.md`](../references/ACTIONS.md) | `actions.json` 字段、placements、`bind.tables`、`bind.selectionMode`、inputSchema、跨表 Lookup、字段条件显隐 `visibleWhen`、本地路径 `file`/`directory` + 可选 **`pathRoot`**、选择摘要「已选择」与映射 **`readOnly` / `revealInForm`**、**按钮中文名 `label` 参考** | +| [`../references/ACTIONS.md`](../references/ACTIONS.md) | `actions.json` 字段、placements、`bind.tables`、`bind.selectionMode`、**用户可见文案**、inputSchema、跨表 Lookup、字段条件显隐 `visibleWhen`、本地路径 `file`/`directory` + 可选 **`pathRoot`**、选择摘要「已选择」与映射 **`readOnly` / `revealInForm`**、**按钮中文名 `label` 参考** | | [`LOGGING.md`](LOGGING.md) | `job_context` / `emit` / `finish` / Run Journal | | [`DATA_PATHS.md`](DATA_PATHS.md) | 下载/导入等落盘路径 | @@ -21,7 +21,7 @@ 1. **宿主管调度,技能管业务** — 不自行实现任务中心 / Job 轮询 / 后台守护进程。 2. **单业务内核、多入口** — 数据管理、定时任务、Agent、技能详情与直接 CLI 复用同一 domain service;禁止按入口复制业务逻辑。 -3. **五职责正交** — `placements` / `bind.tables` / `executionProfile` / `entrypoint` / domain service 各管一事(见 ACTIONS.md)。可选第六轴 **policy**(见 `references/POLICY.md`):未启用 = L0 与今日一致。可选 **`hostEffects` / `steps`**(见 ACTIONS.md):数据管理交互前后的 UI/级联编排;省略 = 不额外改 UI(匠厂宿主 ≥2.8.5)。可选 **`hoverHint`**(见 ACTIONS.md):数据管理工具栏悬停;省略 = 不显示,不回退说明或确认黄条。可选 **`visibleWhen`**(见 ACTIONS.md):Action 参数表单字段条件显隐;省略 = 字段始终平铺;**勿与** Policy L3 行态 `visibleWhen` 混淆;**勿**用其藏映射主键。可选 **`pathRoot`**(见 ACTIONS.md):`file`/`directory` 原生选路对话框起始目录(相对技能数据根;省略默认 `{skill_data}/input`)。可选 **`bind.labelColumn`**(见 ACTIONS.md):选择摘要可读标签列;省略 = 宿主常见列名启发。可选 **`bind.selectionMode`**(见 ACTIONS.md):表勾选如何驱动 Action(`required` / `none` / `optional`);省略 = 宿主按 `$selection.ids` / `batch` 推断。可选 **`revealInForm`**(见 ACTIONS.md):有「已选择」时仍强制显示某 `readOnly` 字段;省略 = 映射只读默认不占 form 参数区(仍提交)。可选 **`cellPresentation`**(见 `references/CELL_PRESENTATION.md`):单元格语义标色;省略 = P0。 +3. **五职责正交** — `placements` / `bind.tables` / `executionProfile` / `entrypoint` / domain service 各管一事(见 ACTIONS.md)。可选第六轴 **policy**(见 `references/POLICY.md`):未启用 = L0 与今日一致。可选 **`hostEffects` / `steps`**(见 ACTIONS.md):数据管理交互前后的 UI/级联编排;省略 = 不额外改 UI(匠厂宿主 ≥2.8.5)。可选 **`hoverHint`**(见 ACTIONS.md):数据管理工具栏悬停;省略 = 不显示,不回退说明或确认黄条。可选 **`visibleWhen`**(见 ACTIONS.md):Action 参数表单字段条件显隐;省略 = 字段始终平铺;**勿与** Policy L3 行态 `visibleWhen` 混淆;**勿**用其藏映射主键。可选 **`pathRoot`**(见 ACTIONS.md):`file`/`directory` 原生选路对话框起始目录(相对技能数据根;省略默认 `{skill_data}/input`)。可选 **`bind.labelColumn`**(见 ACTIONS.md):选择摘要可读标签列;省略 = 宿主常见列名启发。可选 **`bind.selectionMode`**(见 ACTIONS.md):表勾选如何驱动 Action(`required` / `none` / `optional`);省略 = 宿主按 `$selection.ids` / `batch` 推断。可选 **`revealInForm`**(见 ACTIONS.md):有「已选择」时仍强制显示某 `readOnly` 字段;省略 = 映射只读默认不占 form 参数区(仍提交)。可选 **`cellPresentation`**(见 `references/CELL_PRESENTATION.md`):单元格语义标色;省略 = P0。**用户可见文案**(见 ACTIONS.md「用户可见文案」):弹窗 `description` / 确认黄条 / 参数说明 / 任务失败 `message` 须全中文产品用语;Agent 路由勿塞进弹窗。 4. **长耗时建议 async** — 开浏览器、RPA、HTTP 大文件下载等建议 `executionProfile: "async"`,进**任务中心**;这是对**方法**的选择,**不**限制可以出现在哪些 placement / 入口。 5. **Agent:短 CLI / 长 Action** — 短查询可用共享 Python bash CLI;长任务 / RPA **禁止** `exec` + `process poll`,必须 `run_skill_action`。 6. **进度走 Journal** — `emit` / `video.add_step` → Run Journal;UI / Skill Run Card / 任务中心展示;**不靠 stdout 流**。 diff --git a/references/ACTIONS.md b/references/ACTIONS.md index 1b340b2..c58f94a 100644 --- a/references/ACTIONS.md +++ b/references/ACTIONS.md @@ -167,6 +167,47 @@ Action 是否提供、挂哪些 `placements`,由本技能 **入口定位表** 示例:[`assets/examples/selection-mode-optional.action.example.json`](../assets/examples/selection-mode-optional.action.example.json)。 +弹窗上的 `description` / 参数说明须用**普通用户中文**(见下节「用户可见文案」);`pickCount` 等只作 **property 名 / CLI 参数名**,不要写进用户可读句子。 + +### 用户可见文案(双受众,必读) + +宿主会把下列字段**原样展示给普通用户**(数据管理弹窗、任务中心时间线、表说明等): + +| 字段 | 出现位置 | +|------|----------| +| Action `description` | 弹窗顶部说明 | +| `confirmation.message` | 确认/表单黄条 | +| `inputSchema` 各字段 `title` / `description` | 参数区标签与帮助 | +| CLI / `finish` 返回的用户向 `message` | 任务中心、失败摘要 | +| 表/列 `display_name`、表 `description` | 数据管理侧栏与表头帮助 | + +**总原则:** 以上文案 = **产品用语、全中文**。Agent 路由禁令、实现细节、契约自述放在 **`SKILL.md` / `references/`**,**不要**塞进弹窗 `description`。 + +**允许写:** 待下载、任务中心、打开浏览器、有勾选 / 没有勾选、下载数量、按钮中文名(如「导入待下载链接」)。 + +**禁止写进用户文案(常见反例):** + +| 类型 | 反例 | +|------|------| +| 字段名 / CLI 子命令 | `pickCount`、`itemIds`、`import-urls`、`enqueue` | +| 英文状态 / 条件式 | `pending`、`status=pending`、`failed` | +| 执行剖面黑话 | `async`、`sync`、单独甩 `Job`(可说「任务中心」) | +| Agent 禁令 | 「不是明确 URL 入口」「不要先 download-enqueue…」 | +| 契约自述 | 「示例:bind.selectionMode=optional」 | + +**对照:** + +| 差(开发者备注) | 好(普通用户) | +|------------------|----------------| +| 按 `pickCount` 从 `pending` 领取(async) | 没有勾选则按下方数量从待下载队列领取;进度可在任务中心查看 | +| 请先 import-urls | 请先在数据管理录入链接,或使用「导入待下载链接」 | + +**边界:** + +- `inputSchema` **属性名**、`entrypoint` 参数、库表状态枚举值可以仍是英文;变的是 **title / description / message**。 +- `label` 仍遵循上文「Action 按钮中文名」;本节约束的是说明与帮助文字。 +- 与 `bind.selectionMode` 正交:行为对了,文案仍须对人说人话。 + ### 数据管理:选择摘要(宿主默认能力) 当用户在数据管理**勾选行**(或行内打开带行上下文的动作)后打开 `confirm` / `form` 弹层时,若当前 Action 的 `selectionMode` 会**应用**表勾选(`required`,或 `optional` 且已勾选),宿主会展示通用 **「已选择 · N 条」** 摘要(`#主键` + 可读标签;超过约 3 条可展开查看全部)。这是**宿主 UX**,对适用技能默认生效: diff --git a/scripts/util/constants.py b/scripts/util/constants.py index 1878a10..2b247b6 100644 --- a/scripts/util/constants.py +++ b/scripts/util/constants.py @@ -1,6 +1,6 @@ """技能标识、版本与平台公共库约束(复制后请修改 slug/version/logger)。""" SKILL_SLUG = "your-skill-slug" -SKILL_VERSION = "1.0.107" +SKILL_VERSION = "1.0.108" LOG_LOGGER_NAME = "openclaw.skill.your_skill_slug" PLATFORM_KIT_MIN_VERSION = "1.2.11" diff --git a/tests/test_actions_manifest.py b/tests/test_actions_manifest.py index ce72830..84de4f2 100644 --- a/tests/test_actions_manifest.py +++ b/tests/test_actions_manifest.py @@ -522,6 +522,59 @@ class TestActionsManifest(unittest.TestCase): } jsonschema.validate(instance=manifest, schema=schema) + def test_action_examples_user_facing_copy_avoids_jargon(self) -> None: + """示例 Action 的用户可见字符串不得含常见开发黑话(属性名本身除外)。""" + examples_dir = os.path.join(get_skill_root(), "assets", "examples") + # 故意拆开,避免本测试源码触发自身扫描。 + forbidden = ( + "pickCount", + "itemIds", + "status=", + "import-urls", + "download-enqueue", + "bind.selectionMode", + "selectionMode=", + ) + # async/pending 作为整词出现在 description 才禁止;executionProfile 值除外。 + word_forbidden = re.compile(r"\b(async|pending|sync)\b", re.I) + + for name in os.listdir(examples_dir): + if not name.endswith(".action.example.json"): + continue + path = os.path.join(examples_dir, name) + with open(path, encoding="utf-8") as f: + data = json.load(f) + actions = data["actions"] if isinstance(data, dict) and "actions" in data else [data] + for action in actions: + if not isinstance(action, dict): + continue + texts: list[str] = [] + for key in ("description",): + if action.get(key): + texts.append(str(action[key])) + conf = action.get("confirmation") or {} + if isinstance(conf, dict) and conf.get("message"): + texts.append(str(conf["message"])) + props = ((action.get("inputSchema") or {}).get("properties")) or {} + for prop in props.values(): + if not isinstance(prop, dict): + continue + for key in ("title", "description"): + if prop.get(key): + texts.append(str(prop[key])) + blob = "\n".join(texts) + for token in forbidden: + self.assertNotIn( + token, + blob, + msg=f"{name} user-facing copy must not contain {token!r}", + ) + match = word_forbidden.search(blob) + if match is not None: + self.fail( + f"{name} user-facing copy must not contain {match.group(0)!r}" + ) + def test_no_execution_profile_placement_coupling_in_tests(self) -> None: """守护:本文件不得引入入口位置与 sync/async 的错误硬耦合断言。""" path = os.path.join(get_skill_root(), "tests", "test_actions_manifest.py") @@ -686,6 +739,8 @@ class TestActionsManifest(unittest.TestCase): "labelColumn", "selectionMode", "勾选驱动", + "用户可见文案", + "双受众", "已选择", "revealInForm", "映射只读", diff --git a/tests/test_docs_standards.py b/tests/test_docs_standards.py index 8517783..648f2b5 100644 --- a/tests/test_docs_standards.py +++ b/tests/test_docs_standards.py @@ -423,10 +423,16 @@ class TestDocsStandards(unittest.TestCase): self.assertIn("revealInForm", checklist) self.assertIn("A4-9", checklist) self.assertIn("selectionMode", checklist) + self.assertIn("A4-10", checklist) + self.assertIn("用户可见文案", checklist) runtime = self._read("development/SKILL_ACTION_RUNTIME.md") self.assertIn("visibleWhen", runtime) self.assertIn("revealInForm", runtime) self.assertIn("selectionMode", runtime) + self.assertIn("用户可见文案", runtime) + actions = self._read("references/ACTIONS.md") + self.assertIn("用户可见文案", actions) + self.assertIn("双受众", actions) def test_guarded_docs_do_not_reference_amazon_implementation(self) -> None: forbidden = (