1
0

feat: 配置变量系统与 target id/name 双字段标识

- 新增顶层 variables 段支持 string/number/boolean 字面量
- target 字符串字段支持 、、{...} 转义语法
- 变量解析优先级: variables -> process.env -> 默认值 -> 报错
- 完整引用保留原始类型,部分引用拼接为字符串
- 变量替换在 YAML 解析后、AJV 校验前执行
- 替换仅作用于 targets,跳过 id/type 字段
- target 新增必填 id 字段作为唯一标识,name 改为可选展示名称
- 数据库存储/API/前端全面迁移到 id 标识
- 统一 checker 运行时类型检查为 es-toolkit predicates
- 同步 delta specs 到主 specs,归档 config-variables 变更
This commit is contained in:
2026-05-17 00:37:54 +08:00
parent 366b3211c8
commit 7926514986
53 changed files with 1538 additions and 333 deletions

View File

@@ -0,0 +1,170 @@
## Purpose
定义配置文件的变量定义、引用、解析和替换机制,支持集中管理共享值和环境变量注入。
## Requirements
### Requirement: variables 段定义
配置文件 SHALL 支持可选的顶层 `variables`用于定义变量键值对。variables 的 key SHALL 符合 `[a-zA-Z_][a-zA-Z0-9_]*` 命名规则。variables 的 value SHALL 仅支持 string、number、boolean 三种类型MUST NOT 支持 null、array、object。variables 段自身 MUST NOT 支持引用其他变量或环境变量(值为纯字面量)。
#### Scenario: 定义字符串变量
- **WHEN** 配置文件包含 `variables: { base_url: "https://api.example.com" }`
- **THEN** 系统 SHALL 解析 base_url 为字符串类型变量,值为 "https://api.example.com"
#### Scenario: 定义数字变量
- **WHEN** 配置文件包含 `variables: { port: 5432 }`
- **THEN** 系统 SHALL 解析 port 为 number 类型变量,值为 5432
#### Scenario: 定义布尔变量
- **WHEN** 配置文件包含 `variables: { ssl_enabled: true }`
- **THEN** 系统 SHALL 解析 ssl_enabled 为 boolean 类型变量,值为 true
#### Scenario: 变量值为 null 报错
- **WHEN** 配置文件包含 `variables: { empty: null }`
- **THEN** 系统 SHALL 以配置错误退出,提示 variables 的值不允许为 null
#### Scenario: 变量值为数组报错
- **WHEN** 配置文件包含 `variables: { list: [1, 2, 3] }`
- **THEN** 系统 SHALL 以配置错误退出,提示 variables 的值不允许为 array
#### Scenario: 变量值为对象报错
- **WHEN** 配置文件包含 `variables: { obj: { a: 1 } }`
- **THEN** 系统 SHALL 以配置错误退出,提示 variables 的值不允许为 object
#### Scenario: 变量 key 不合法报错
- **WHEN** 配置文件包含 `variables: { "123start": "value" }`
- **THEN** 系统 SHALL 以配置错误退出,提示变量名不符合命名规则
#### Scenario: 不定义 variables 段
- **WHEN** 配置文件不包含 variables 段
- **THEN** 系统 SHALL 正常启动targets 中的 `${...}` 引用仅从环境变量查找
### Requirement: 变量引用语法
targets 中的字符串值 SHALL 支持 `${key}` 语法引用变量。系统 SHALL 支持 `${key|default}` 语法设置默认值,其中第一个 `|` 为分隔符,后续 `|` 属于默认值内容。系统 SHALL 支持 `$${...}` 转义语法输出字面量 `${...}`
#### Scenario: 简单变量引用
- **WHEN** target 字段值为 `"${base_url}/health"` 且 variables 中定义 `base_url: "https://api.example.com"`
- **THEN** 系统 SHALL 将该字段替换为 `"https://api.example.com/health"`
#### Scenario: 带默认值的变量引用
- **WHEN** target 字段值为 `"${DB_PORT|5432}"` 且 variables 和环境变量中均不存在 DB_PORT
- **THEN** 系统 SHALL 将该字段替换为使用默认值(类型推断后为 number 5432
#### Scenario: 默认值包含管道符
- **WHEN** target 字段值为 `"${PATTERN|foo|bar}"` 且变量不存在
- **THEN** 系统 SHALL 使用 `"foo|bar"` 作为默认值(第一个 `|` 为分隔符)
#### Scenario: 转义语法
- **WHEN** target 字段值为 `"Hello $${name}"`
- **THEN** 系统 SHALL 输出 `"Hello ${name}"`,不进行变量替换
#### Scenario: 多个变量引用
- **WHEN** target 字段值为 `"${protocol}://${host}:${port}/api"`
- **THEN** 系统 SHALL 逐个解析并替换所有变量引用,结果为拼接后的字符串
#### Scenario: 无变量引用的字符串
- **WHEN** target 字段值为 `"https://example.com"` 且不含 `${...}` 模式
- **THEN** 系统 SHALL 保持原样,不做任何处理
### Requirement: 变量解析优先级
系统 SHALL 按以下优先级解析变量引用variables 定义 → 环境变量 → 默认值。如果三者均不存在,系统 SHALL 以配置错误退出。
#### Scenario: variables 优先于环境变量
- **WHEN** variables 中定义 `port: 5432` 且环境变量 `port=3000` 也存在
- **THEN** 系统 SHALL 使用 variables 中的值 5432
#### Scenario: 环境变量作为 fallback
- **WHEN** variables 中未定义 `DB_HOST` 但环境变量 `DB_HOST=localhost` 存在
- **THEN** 系统 SHALL 使用环境变量的值 "localhost"
#### Scenario: 默认值作为最终 fallback
- **WHEN** variables 和环境变量中均不存在 `CACHE_TTL`,且引用为 `${CACHE_TTL|60}`
- **THEN** 系统 SHALL 使用默认值(类型推断后为 number 60
#### Scenario: 变量未定义且无默认值报错
- **WHEN** target 字段引用 `${MISSING_VAR}` 且 variables、环境变量中均不存在也未设置默认值
- **THEN** 系统 SHALL 以配置错误退出,提示该变量未定义
### Requirement: 完整引用类型保留
当字段值仅包含单个变量引用(完整引用)时,系统 SHALL 保留变量的原始类型。完整引用的判定为:字段值去掉首尾空白后严格匹配单个 `${key}``${key|default}` 模式且无其他字符。
#### Scenario: 完整引用 number 变量
- **WHEN** target 字段值为 `"${port}"` 且 variables 中 `port: 5432`
- **THEN** 系统 SHALL 将该字段替换为 number 类型的 5432
#### Scenario: 完整引用 boolean 变量
- **WHEN** target 字段值为 `"${ssl}"` 且 variables 中 `ssl: true`
- **THEN** 系统 SHALL 将该字段替换为 boolean 类型的 true
#### Scenario: 完整引用 string 变量
- **WHEN** target 字段值为 `"${host}"` 且 variables 中 `host: "example.com"`
- **THEN** 系统 SHALL 将该字段替换为 string 类型的 "example.com"
#### Scenario: 部分引用强制为字符串
- **WHEN** target 字段值为 `"port: ${port}"` 且 variables 中 `port: 5432`
- **THEN** 系统 SHALL 将该字段替换为 string 类型的 "port: 5432"
#### Scenario: 环境变量完整引用类型推断
- **WHEN** target 字段值为 `"${MAX_REDIRECTS}"` 且环境变量 `MAX_REDIRECTS=5`
- **THEN** 系统 SHALL 将该字段替换为 number 类型的 5类型推断
#### Scenario: 默认值完整引用类型推断
- **WHEN** target 字段值为 `"${TIMEOUT|30}"` 且变量不存在
- **THEN** 系统 SHALL 将该字段替换为 number 类型的 30类型推断
#### Scenario: 默认值推断为 boolean
- **WHEN** target 字段值为 `"${IGNORE_SSL|false}"` 且变量不存在
- **THEN** 系统 SHALL 将该字段替换为 boolean 类型的 false
#### Scenario: 默认值无法推断保持字符串
- **WHEN** target 字段值为 `"${HOST|localhost}"` 且变量不存在
- **THEN** 系统 SHALL 将该字段替换为 string 类型的 "localhost"
### Requirement: 替换范围限制
变量替换 SHALL 仅作用于 targets 段。`id``type` 字段 MUST NOT 参与变量替换。`server``runtime``defaults` 段 MUST NOT 参与变量替换。系统 SHALL 递归遍历 target 对象树中所有字符串值进行替换(包括嵌套对象和数组元素中的字符串)。
#### Scenario: target 嵌套对象中的变量替换
- **WHEN** target 配置 `http.headers.Authorization: "${token}"` 且 variables 中定义 `token: "Bearer abc"`
- **THEN** 系统 SHALL 将该 header 值替换为 "Bearer abc"
#### Scenario: target 数组元素中的变量替换
- **WHEN** target 配置 `cmd.args: ["--host", "${host}"]` 且 variables 中定义 `host: "localhost"`
- **THEN** 系统 SHALL 将数组第二个元素替换为 "localhost"
#### Scenario: id 字段不替换
- **WHEN** target 配置 `id: "${my_id}"` 且 variables 中定义 `my_id: "test"`
- **THEN** 系统 SHALL 保持 id 字段值为字面量 `"${my_id}"`,不进行替换
#### Scenario: type 字段不替换
- **WHEN** target 配置 `type: "${checker_type}"` 且 variables 中定义 `checker_type: "http"`
- **THEN** 系统 SHALL 保持 type 字段值为字面量 `"${checker_type}"`,不进行替换
#### Scenario: defaults 段不替换
- **WHEN** defaults 配置 `interval: "${default_interval}"` 且 variables 中定义 `default_interval: "30s"`
- **THEN** 系统 SHALL 保持 defaults.interval 为字面量 `"${default_interval}"`,不进行替换
#### Scenario: server 段不替换
- **WHEN** server 配置 `host: "${server_host}"` 且 variables 中定义 `server_host: "0.0.0.0"`
- **THEN** 系统 SHALL 保持 server.host 为字面量 `"${server_host}"`,不进行替换
### Requirement: 变量替换错误报告
变量替换阶段的错误 SHALL 作为 `ConfigValidationIssue` 输出code 为 `unresolved-variable`。错误信息 SHALL 包含 target 索引、target id、字段路径和变量名。
#### Scenario: 单个变量缺失报错
- **WHEN** targets[0] (id: "api-health") 的 http.url 引用 `${base_url}` 但变量不存在
- **THEN** 系统 SHALL 输出包含 target 索引 0、id "api-health"、路径 "http.url"、变量名 "base_url" 的错误信息
#### Scenario: 多个变量缺失批量报错
- **WHEN** 多个 target 的多个字段引用了不存在的变量
- **THEN** 系统 SHALL 收集所有缺失变量错误后统一输出,而非遇到第一个就退出
### Requirement: 变量替换执行时机
变量替换 SHALL 在 YAML 解析之后、schema 契约校验AJV之前执行。替换完成后的配置对象 SHALL 传入后续校验流程。
#### Scenario: 替换后通过 schema 校验
- **WHEN** target 配置 `http.maxRedirects: "${MAX_REDIRECTS}"` 且环境变量 `MAX_REDIRECTS=5`
- **THEN** 系统 SHALL 先将该字段替换为 number 5再进入 AJV 校验(期望 integer校验通过
#### Scenario: 替换后未通过 schema 校验
- **WHEN** target 配置 `http.maxRedirects: "${MAX_REDIRECTS}"` 且环境变量 `MAX_REDIRECTS=abc`
- **THEN** 系统 SHALL 先将该字段替换为 string "abc",再进入 AJV 校验(期望 integer校验失败并报错

View File

@@ -5,21 +5,21 @@
## Requirements
### Requirement: YAML 配置文件格式
系统 SHALL 支持通过 YAML 配置文件定义全部运行参数,包括 server 配置、runtime 配置、checker 默认值和 typed target 列表(含可选 group 字段。target MUST 使用 `type` 字段声明 checker 类型,HTTP 领域字段 MUST 放在 `http` 分组cmd 领域字段 MUST 放在 `cmd` 分组db 领域字段 MUST 放在 `db` 分组。HTTP target 的 `http` 分组 SHALL 支持可选的 `ignoreSSL`(布尔值)和 `maxRedirects`非负整数字段。Db target 的 `db` 分组 SHALL 支持 `url`(必填)和 `query`(可选)字段。
系统 SHALL 支持通过 YAML 配置文件定义全部运行参数,包括 server 配置、runtime 配置、可选的 variables 段、checker 默认值和 typed target 列表(含可选 group 字段。target MUST 使用 `id` 字段作为唯一标识符MUST 使用 `type` 字段声明 checker 类型SHALL 支持可选的 `name` 字段作为展示名称(缺省 fallback 到 idHTTP 领域字段 MUST 放在 `http` 分组cmd 领域字段 MUST 放在 `cmd` 分组db 领域字段 MUST 放在 `db` 分组。HTTP target 的 `http` 分组 SHALL 支持可选的 `ignoreSSL`(布尔值)和 `maxRedirects`非负整数字段。Db target 的 `db` 分组 SHALL 支持 `url`(必填)和 `query`(可选)字段。
`defaults.http` 分组 SHALL 仅支持 `headers`(可选)和 `maxBodyBytes`(可选)字段。`defaults.http` 分组 MUST NOT 支持 `method` 字段。
#### Scenario: 完整配置文件解析
- **WHEN** 系统启动并读取包含 server、runtime、defaults、targets含 group 字段)的 YAML 配置文件
- **WHEN** 系统启动并读取包含 server、runtime、variables、defaults、targetsid、group 字段)的 YAML 配置文件
- **THEN** 系统 SHALL 正确解析所有字段并用于初始化服务、调度引擎和对应 checker runner
#### Scenario: 最简 HTTP 配置文件解析
- **WHEN** 系统读取只包含一个 `type: http` target 和 `http.url` 的 YAML 配置文件(省略 server、runtime、defaults 和 expect
- **THEN** 系统 SHALL 使用内置默认值填充未指定的字段host=127.0.0.1, port=3000, dir=./data, interval=30s, timeout=10s, runtime.maxConcurrentChecks=20, http.method=GET, http.maxBodyBytes=100MB, http.ignoreSSL=false, http.maxRedirects=0, group="default"
- **WHEN** 系统读取只包含一个 `type: http` target(含 `id``http.url`的 YAML 配置文件(省略 server、runtime、variables、defaults 和 expect
- **THEN** 系统 SHALL 使用内置默认值填充未指定的字段host=127.0.0.1, port=3000, dir=./data, interval=30s, timeout=10s, runtime.maxConcurrentChecks=20, http.method=GET, http.maxBodyBytes=100MB, http.ignoreSSL=false, http.maxRedirects=0, group="default", name fallback 到 id
#### Scenario: 最简 cmd 配置文件解析
- **WHEN** 系统读取只包含一个 `type: cmd` target 和 `cmd.exec` 的 YAML 配置文件
- **THEN** 系统 SHALL 使用内置默认值填充未指定的字段interval=30s, timeout=10s, cmd.cwd 为配置文件所在目录, cmd.maxOutputBytes=100MB
- **WHEN** 系统读取只包含一个 `type: cmd` target(含 `id``cmd.exec`的 YAML 配置文件
- **THEN** 系统 SHALL 使用内置默认值填充未指定的字段interval=30s, timeout=10s, cmd.cwd 为配置文件所在目录, cmd.maxOutputBytes=100MB, name fallback 到 id
#### Scenario: per-target 配置覆盖全局默认值
- **WHEN** 某个 target 指定 interval、timeout 或对应领域分组中的默认字段
@@ -34,8 +34,8 @@
- **THEN** 系统 SHALL 解析该字段并在执行时允许最多跟随 5 次重定向
#### Scenario: 最简 db 配置文件解析
- **WHEN** 系统读取只包含一个 `type: db` target 和 `db.url` 的 YAML 配置文件
- **THEN** 系统 SHALL 使用内置默认值填充未指定的字段interval=30s, timeout=10s, group="default"
- **WHEN** 系统读取只包含一个 `type: db` target(含 `id``db.url`的 YAML 配置文件
- **THEN** 系统 SHALL 使用内置默认值填充未指定的字段interval=30s, timeout=10s, group="default", name fallback 到 id
#### Scenario: defaults.http.method 触发校验错误
- **WHEN** 配置文件中出现 `defaults.http.method` 字段
@@ -65,16 +65,16 @@
- **THEN** 系统 SHALL 以错误退出并提示文件不存在
### Requirement: 配置校验
系统 SHALL 在启动时对 YAML 配置进行完整校验,校验失败时以非零状态退出并输出清晰的错误信息。系统 SHALL 使用 TypeBox 定义配置契约和 raw config TypeScript 类型,由 Ajv 校验 TypeBox 生成的 JSON Schema再执行启动期语义 validator。配置加载流程 SHALL 明确区分 `RawProbeConfig``ValidatedProbeConfig``ResolvedConfig` 三段生命周期。JSON Schema 契约 SHALL 覆盖业务无关的结构规则,包括字段类型、必填字段、枚举、数组与对象形状、数值范围和未知字段。语义 validator SHALL 覆盖契约不适合表达的业务规则,包括 target name 唯一性、checker type 注册状态、时长和大小解析、HTTP URL、正则可编译、JSONPath 子集和 XPath 可编译。
系统 SHALL 在启动时对 YAML 配置进行完整校验,校验失败时以非零状态退出并输出清晰的错误信息。系统 SHALL 使用 TypeBox 定义配置契约和 raw config TypeScript 类型,由 Ajv 校验 TypeBox 生成的 JSON Schema再执行启动期语义 validator。配置加载流程 SHALL 明确区分 `RawProbeConfig``ValidatedProbeConfig``ResolvedConfig` 三段生命周期,并在 YAML 解析之后、AJV 校验之前执行变量替换阶段。JSON Schema 契约 SHALL 覆盖业务无关的结构规则,包括字段类型、必填字段、枚举、数组与对象形状、数值范围和未知字段。语义 validator SHALL 覆盖契约不适合表达的业务规则,包括 target id 唯一性、id 命名规则校验、checker type 注册状态、时长和大小解析、HTTP URL、正则可编译、JSONPath 子集和 XPath 可编译。
契约校验和语义 validator SHALL 统一产出 `ConfigValidationIssue`,最终由配置加载流程统一渲染为中文错误信息。
系统 SHALL 导出完整 `probe-config.schema.json`,该文件 SHALL 与运行期 TypeBox fragments 生成的 JSON Schema 保持一致,用于用户配置引用和编辑器提示。
`headers``env` 等明确声明为动态键值表的对象外,配置中的未知字段 SHALL 导致启动期配置错误。系统 MUST NOT 静默忽略未知字段。
`headers``env``variables` 等明确声明为动态键值表的对象外,配置中的未知字段 SHALL 导致启动期配置错误。系统 MUST NOT 静默忽略未知字段。
#### Scenario: target 缺少必填字段
- **WHEN** YAML 中某个 target 缺少 name 或 type 字段
- **WHEN** YAML 中某个 target 缺少 id 或 type 字段
- **THEN** 系统 SHALL 以错误退出,提示哪个 target 缺少哪个字段
#### Scenario: HTTP target 缺少 url
@@ -89,9 +89,13 @@
- **WHEN** YAML 中某个 target 的 type 不是已注册 checker 类型
- **THEN** 系统 SHALL 以错误退出,提示不支持的 target type 和当前支持的 type 列表
#### Scenario: target name 重复
- **WHEN** YAML 中存在两个 name 相同的 target
- **THEN** 系统 SHALL 以错误退出,提示重复的 name
#### Scenario: target id 重复
- **WHEN** YAML 中存在两个 id 相同的 target
- **THEN** 系统 SHALL 以错误退出,提示重复的 id
#### Scenario: target id 不合法
- **WHEN** YAML 中某个 target 的 id 不符合 `[a-zA-Z0-9][a-zA-Z0-9_-]*` 规则
- **THEN** 系统 SHALL 以错误退出,提示 id 命名不合法
#### Scenario: group 字段类型校验
- **WHEN** YAML 中某个 target 的 `group` 字段不是字符串
@@ -223,15 +227,15 @@
#### Scenario: 配置生命周期分离
- **WHEN** 系统加载配置文件
- **THEN** 系统 SHALL 按 `unknown -> RawProbeConfig -> ValidatedProbeConfig -> ResolvedConfig` 的顺序执行契约校验、语义校验和运行期配置解析
- **THEN** 系统 SHALL 按 `unknown -> 变量替换 -> RawProbeConfig -> ValidatedProbeConfig -> ResolvedConfig` 的顺序执行变量替换、契约校验、语义校验和运行期配置解析
#### Scenario: 结构化校验 issue
- **WHEN** 契约校验语义 validator 发现非法配置
- **THEN** 系统 SHALL 先生成包含 code、path、message 和可选 targetName 的结构化 `ConfigValidationIssue`,再统一渲染为中文错误
- **WHEN** 契约校验语义 validator 或变量替换阶段发现非法配置
- **THEN** 系统 SHALL 先生成包含 code、path、message 和可选 targetName 的结构化 `ConfigValidationIssue`,再统一渲染为中文错误信息
#### Scenario: 导出配置 JSON Schema
- **WHEN** 仓库生成或检查配置契约
- **THEN** 根目录 SHALL 存在 draft-07 `probe-config.schema.json`,且其内容 SHALL 与当前公共 fragments 和已注册 checker fragments 组装出的完整 schema 一致
- **THEN** 根目录 SHALL 存在 draft-07 `probe-config.schema.json`,且其内容 SHALL 与当前公共 fragments 和已注册 checker fragments 组装出的完整 schema 一致(包含 variables 段和 target 的 id/name 字段)
系统 SHALL 支持使用单位字符串配置读取上限,单位包括 `B``KB``MB``GB`
#### Scenario: 解析 MB

View File

@@ -34,7 +34,7 @@
#### Scenario: 配置变更后重新同步
- **WHEN** YAML 配置发生变更(新增、删除或修改目标)后重启
- **THEN** 系统 SHALL 根据 name 字段匹配:新增的插入、删除的移除、修改的更新(含 grp 字段)
- **THEN** 系统 SHALL 根据 id 字段匹配:新增的插入、删除的移除、修改的更新(含 grp 字段)
### Requirement: check_results 表追加写入
系统 SHALL 将每次检查结果追加写入 check_results 表,不更新或删除已有记录。

View File

@@ -0,0 +1,51 @@
## Purpose
定义 target 的 id/name 双字段标识体系id 作为唯一标识符name 作为可选展示名称。
## Requirements
### Requirement: target id 字段
每个 target SHALL 包含必填的 `id` 字段作为唯一标识符。`id` SHALL 符合 `[a-zA-Z0-9][a-zA-Z0-9_-]*` 命名规则。`id` MUST 在所有 targets 中全局唯一。`id` MUST NOT 参与变量替换。
#### Scenario: 合法 id
- **WHEN** target 配置 `id: "api-health"`
- **THEN** 系统 SHALL 使用该 id 作为 target 的唯一标识符
#### Scenario: id 包含下划线和连字符
- **WHEN** target 配置 `id: "db_check-01"`
- **THEN** 系统 SHALL 使用该 id 作为 target 的唯一标识符
#### Scenario: id 缺失报错
- **WHEN** target 未配置 `id` 字段
- **THEN** 系统 SHALL 以配置错误退出,提示该 target 缺少 id 字段
#### Scenario: id 为空字符串报错
- **WHEN** target 配置 `id: ""`
- **THEN** 系统 SHALL 以配置错误退出,提示 id 不能为空
#### Scenario: id 不合法报错
- **WHEN** target 配置 `id: "_invalid"``id: "-start"``id: "has space"`
- **THEN** 系统 SHALL 以配置错误退出,提示 id 不符合命名规则
#### Scenario: id 重复报错
- **WHEN** 两个 target 配置相同的 `id: "api-health"`
- **THEN** 系统 SHALL 以配置错误退出,提示 id 重复
### Requirement: target name 字段
每个 target SHALL 支持可选的 `name` 字段作为展示名称。`name` 缺省时 SHALL fallback 到 `id` 的值作为展示名称。`name` SHALL 支持变量替换。`name` MUST NOT 要求全局唯一。
#### Scenario: 配置 name
- **WHEN** target 配置 `id: "api-health"``name: "API 健康检查"`
- **THEN** 系统 SHALL 使用 "API 健康检查" 作为展示名称
#### Scenario: name 使用变量
- **WHEN** target 配置 `name: "${env} API 健康检查"` 且 variables 中 `env: "生产"`
- **THEN** 系统 SHALL 将展示名称解析为 "生产 API 健康检查"
#### Scenario: name 缺省 fallback 到 id
- **WHEN** target 配置 `id: "api-health"` 但未配置 `name`
- **THEN** 系统 SHALL 使用 "api-health" 作为展示名称
#### Scenario: 多个 target 使用相同 name
- **WHEN** 两个 target 配置不同 id 但相同 `name: "健康检查"`
- **THEN** 系统 SHALL 接受该配置不报错name 不要求全局唯一)