From db2325dbe49fdb422e402ba6491b0e798706c2e9 Mon Sep 17 00:00:00 2001 From: chendelian <116870791@qq.com> Date: Tue, 11 Aug 2026 14:38:32 +0800 Subject: [PATCH] docs: contract for CRUD form description and SQLite DEFAULT prefill (v1.0.76) --- CHANGELOG.md | 6 ++++ SKILL.md | 2 +- references/ACTIONS.md | 14 ++++++++- references/SCHEMA.md | 59 ++++++++++++++++++++++++++++++++++-- scripts/util/constants.py | 2 +- tests/test_docs_standards.py | 13 ++++++++ 6 files changed, 90 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 76fd8e0..d12d2d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ - 小节正文写用户能看懂的变化(新能力、修复、注意事项),避免堆砌内部实现细节 - 打 tag 前**必须**为即将发布的版本新增一节;找不到匹配小节时,本次发布不会更新 changelog 字段 +## 1.0.76 + +- 固化数据管理「新增/编辑」表单契约:列 `description` 须在标签下展示;创建默认值取自 SQLite 列 `DEFAULT`(见 `references/SCHEMA.md`) +- 明确禁止把说明塞进 `display_name`;与 Skill Action 的 `inputSchema.description` / `default` 分工写清(见 `ACTIONS.md`) +- 宿主须按该契约实现下发与预填;技能侧用元数据说明 + DDL DEFAULT 即可,第一期不新增表单默认值元数据列 + ## 1.0.75 - 正式沉淀数据管理「单元格呈现」通用契约(`references/CELL_PRESENTATION.md`):技能声明某表某行某列的语义 tone,宿主映射主题样式 diff --git a/SKILL.md b/SKILL.md index b15e441..86c398b 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,7 +1,7 @@ --- name: 技能开发模板(通用业务版) description: "OpenClaw 通用业务技能开发模板,供复制后定制新业务 skill。定制步骤见 development/DEVELOPMENT.md。" -version: 1.0.75 +version: 1.0.76 author: 深圳匠厂科技有限公司 metadata: openclaw: diff --git a/references/ACTIONS.md b/references/ACTIONS.md index d163cd3..35d4b7f 100644 --- a/references/ACTIONS.md +++ b/references/ACTIONS.md @@ -507,8 +507,18 @@ HINT: - `object` / `string` / `number` / `boolean` - `enum` / `default` / `required` / `sensitive` / `readOnly` +- 属性级 `description`(表单标签下方灰字说明) - 简单模板替换(`{{fieldName}}`) +**与数据管理「新增 / 编辑」表单的分工(勿混用配置入口):** + +| 表单 | 短标题 | 说明灰字 | 默认值 | +|------|--------|----------|--------| +| Skill Action 弹窗 | `inputSchema.title` | `inputSchema.description` | `inputSchema.default` | +| 数据管理新增/编辑 | `_jiangchang_columns.display_name` | `_jiangchang_columns.description` | 物理列 SQLite `DEFAULT` | + +CRUD 侧宿主义务与禁止事项见 [`SCHEMA.md`](SCHEMA.md)「新增/编辑表单:字段说明与默认值(宿主支持)」。同一业务含义两边文案应对齐,但分别配置。 + 示例: ```json @@ -519,11 +529,13 @@ HINT: "properties": { "query": { "type": "string", - "title": "查询条件" + "title": "查询条件", + "description": "支持关键词或完整业务编号" }, "limit": { "type": "number", "title": "返回数量", + "description": "最多返回多少条;填 0 表示不限制(若业务支持)", "default": 50 } } diff --git a/references/SCHEMA.md b/references/SCHEMA.md index ae504e1..6f383ea 100644 --- a/references/SCHEMA.md +++ b/references/SCHEMA.md @@ -10,7 +10,8 @@ - 定义真实 SQLite 表结构 - 使用英文 `snake_case` 表名和字段名 - 使用 `_jiangchang_tables` 提供表级展示元数据 -- 使用 `_jiangchang_columns` 提供字段级展示元数据 +- 使用 `_jiangchang_columns` 提供字段级展示元数据(含可选 `description` 字段说明) +- 需要「新增表单预填」时,在物理列上声明 SQLite `DEFAULT`(勿把默认值只写在文案里) - 定义哪些字段可见、可搜索、可创建、可编辑 - 定义字段展示类型和枚举选项 - (可选)按业务规则维护单元格呈现旁路数据(语义 tone;见 [`CELL_PRESENTATION.md`](CELL_PRESENTATION.md)) @@ -23,6 +24,8 @@ - 读取 SQLite `PRAGMA table_info` - 根据 schema 渲染数据管理页面 - 根据 `editable` 推导字段是否可创建或编辑 +- 在**新增 / 编辑**表单中,若列有 `_jiangchang_columns.description`,在标签下方展示该说明(灰字;空则不显示) +- 打开**新增**表单时,对可创建字段用 SQLite 列 `DEFAULT`(`PRAGMA table_info.dflt_value`)预填;无 DEFAULT 则留空 - 执行通用查询、新增、编辑、删除、导入、导出 - 对字段名、表名、类型和权限进行最终校验 - 不猜测技能业务含义 @@ -181,8 +184,8 @@ upsert_table_metadata( |------|------|------| | `table_name` | 是 | 所属物理表 | | `column_name` | 是 | 真实英文字段名 | -| `display_name` | 是 | 用户可见的中文字段名 | -| `description` | 否 | 字段说明 | +| `display_name` | 是 | 用户可见的中文字段名(表头与表单标签);保持简短 | +| `description` | 否 | 字段说明(给人看的短文案);**宿主在新增/编辑表单标签下方展示**(见下节);不要塞进 `display_name` | | `display_order` | 否 | 兼容字段,默认保持 `NULL` | | `visible` | 是 | 是否在数据管理表格中展示 | | `searchable` | 是 | 是否参与搜索 | @@ -192,6 +195,56 @@ upsert_table_metadata( 这两张表是**数据字典**,不是业务数据;宿主不会把它们当作普通业务表展示。 +#### 新增/编辑表单:字段说明与默认值(宿主支持) + +数据管理「新增记录 / 编辑记录」与 Skill Action 弹窗是**两套表单**;CRUD 侧约定如下(交互对齐 Action 的 `inputSchema.description` / `default`,但**配置入口不同**)。 + +| 能力 | 技能写什么 | 宿主做什么 | +|------|------------|------------| +| 字段说明 | `_jiangchang_columns.description`(可选) | 新增/编辑表单中,在标签下方以灰字展示;空则不显示 | +| 创建默认值 | 物理列 SQLite `DEFAULT`(如 `limit_n INTEGER NOT NULL DEFAULT 0`) | 打开「新增」时,对可创建字段预填该默认值;无 DEFAULT 则留空 | +| 编辑已有行 | — | **不**用 DEFAULT 覆盖已有行数据 | +| 表格列头 | 只用 `display_name` | 长说明**不**进入列头 | + +规则与禁止: + +- **推荐**对易填错、语义特殊的可编辑字段写 `description`(示例链接、`0` 表示不限制等);非强制每个字段都有 +- **禁止**把说明硬塞进 `display_name`(如 `评论上限(0不限)`);表头会变脏,也无法与 Action 说明对齐 +- 业务语义(如「0 = 不限制」)写在 `description` 里;宿主只展示,**不**解读业务含义 +- 第一期**不**新增元数据「表单默认值」列;CRUD 默认值 = DDL `DEFAULT`,与 Action 的 `inputSchema.default` 分开配置 +- 同一业务字段若同时出现在 Action 与新增表单,**文案应对齐**(短标题 + 说明),但分别写在 `actions.json` 与 `_jiangchang_columns` / DDL + +示例(可编辑列种子 + DDL 默认): + +```sql +-- 物理列:创建默认 0 +comment_limit INTEGER NOT NULL DEFAULT 0 +``` + +```python +seed_column_metadata_batch( + cursor, + table_name="videos", + columns=( + { + "column_name": "video_url", + "display_name": "视频链接", + "editable": 1, + "description": "填平台视频页链接;需包含可识别的视频路径片段。", + }, + { + "column_name": "comment_limit", + "display_name": "采集评论条数", + "editable": 1, + "description": "最多采多少条。填 0 = 不限制;填正整数则按该数量封顶。", + }, + ), + valid_column_names=physical, +) +``` + +Action 参数表单的 `title` / `description` / `default` 见 [`ACTIONS.md`](ACTIONS.md);勿与本节 CRUD 配置入口混用。 + ## editable 与 createable 的关系 技能模板只维护 `editable` 这一份字段权限声明: diff --git a/scripts/util/constants.py b/scripts/util/constants.py index 2716c9e..17d7fe5 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.73" +SKILL_VERSION = "1.0.76" LOG_LOGGER_NAME = "openclaw.skill.your_skill_slug" PLATFORM_KIT_MIN_VERSION = "1.2.2" diff --git a/tests/test_docs_standards.py b/tests/test_docs_standards.py index d5ffd7a..fbffeb1 100644 --- a/tests/test_docs_standards.py +++ b/tests/test_docs_standards.py @@ -337,9 +337,22 @@ class TestDocsStandards(unittest.TestCase): "options_json", "demo_items", "readonly", + "新增/编辑表单:字段说明与默认值(宿主支持)", + "DEFAULT", + "description", ): self.assertIn(marker, text, msg=f"SCHEMA.md missing {marker!r}") + def test_actions_md_documents_form_schema_split(self) -> None: + text = self._read("references/ACTIONS.md") + for marker in ( + "inputSchema 与参数表单", + "数据管理新增/编辑", + "_jiangchang_columns.description", + "SCHEMA.md", + ): + self.assertIn(marker, text, msg=f"ACTIONS.md missing {marker!r}") + def test_guarded_docs_do_not_reference_amazon_implementation(self) -> None: forbidden = ( "download-settlement-report-amazon",