1
0

refactor: 移除顶层 defaults 配置段,简化为 target 显式字段 > 代码内置默认值

- 移除 DefaultsConfig 类型、ProbeConfig.defaults 字段
- 移除 CheckerSchemas.defaults、ResolveContext.defaults、CheckerValidationInput.defaults
- 更新所有 checker schema/resolve/validate 删除 defaults 合并逻辑
- 更新 config-loader 不再读取传递 defaults
- 更新测试、README、DEVELOPMENT、probes.example.yaml
- 重新生成 probe-config.schema.json(不含 defaults)
- 同步 delta specs 到主规范
- 归档 openspec change
This commit is contained in:
2026-05-21 16:53:12 +08:00
parent e448cb4654
commit 79358ba50d
52 changed files with 196 additions and 940 deletions

View File

@@ -31,7 +31,7 @@
- **THEN** 这些类型 SHALL 全部定义在该 checker 目录的 `types.ts` 中,不在顶层 `types.ts`
#### Scenario: schema.ts 包含 TypeBox schema 定义
- **WHEN** 开发者需要该 checker 的 config/defaults/expect schema
- **WHEN** 开发者需要该 checker 的 configexpect schema
- **THEN** 这些 schema SHALL 定义在该 checker 目录的 `schema.ts`
#### Scenario: execute.ts 包含 Checker 类实现

View File

@@ -5,15 +5,15 @@
## Requirements
### Requirement: Checker 配置契约片段
系统 SHALL 支持 checker 提供自身 TypeBox 配置契约片段,用于描述该 checker 的 defaults 分组、target 领域分组和 expect 分组。公共配置加载模块 SHALL 通过 registry 获取已注册 checker 的契约片段,并组合为启动期 Ajv 契约校验流程和外部 `probe-config.schema.json` 导出流程。
系统 SHALL 支持 checker 提供自身 TypeBox 配置契约片段,用于描述该 checker 的 target 领域分组和 expect 分组。公共配置加载模块 SHALL 通过 registry 获取已注册 checker 的契约片段,并组合为启动期 Ajv 契约校验流程和外部 `probe-config.schema.json` 导出流程。
#### Scenario: HTTP checker 提供契约片段
- **WHEN** HTTP checker 被注册
- **THEN** registry SHALL 能提供 HTTP defaults、HTTP target 和 HTTP expect 的 TypeBox 契约片段
- **THEN** registry SHALL 能提供 HTTP target 和 HTTP expect 的 TypeBox 契约片段
#### Scenario: Cmd checker 提供契约片段
- **WHEN** Cmd checker 被注册
- **THEN** registry SHALL 能提供 Cmd defaults、Cmd target 和 Cmd expect 的 TypeBox 契约片段
- **THEN** registry SHALL 能提供 Cmd target 和 Cmd expect 的 TypeBox 契约片段
#### Scenario: 新 checker 只维护自身契约
- **WHEN** 开发者新增一个 checker 类型

View File

@@ -121,7 +121,7 @@ targets 中的字符串值 SHALL 支持 `${key}` 语法引用变量。系统 SHA
- **THEN** 系统 SHALL 将该字段替换为 string 类型的 "localhost"
### Requirement: 替换范围限制
变量替换 SHALL 仅作用于 targets 段。`id``type` 字段 MUST NOT 参与变量替换。`server``probes``defaults` 段 MUST NOT 参与变量替换。系统 SHALL 递归遍历 target 对象树中所有字符串值进行替换(包括嵌套对象和数组元素中的字符串)。
变量替换 SHALL 仅作用于 targets 段。`id``type` 字段 MUST NOT 参与变量替换。`server``probes` 段 MUST NOT 参与变量替换。系统 SHALL 递归遍历 target 对象树中所有字符串值进行替换(包括嵌套对象和数组元素中的字符串)。顶层 `defaults` 不再是合法配置段,因此不属于变量替换范围。
#### Scenario: target 嵌套对象中的变量替换
- **WHEN** target 配置 `http.headers.Authorization: "${token}"` 且 variables 中定义 `token: "Bearer abc"`
@@ -139,10 +139,6 @@ targets 中的字符串值 SHALL 支持 `${key}` 语法引用变量。系统 SHA
- **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 配置 `listen.host: "${server_host}"` 且 variables 中定义 `server_host: "0.0.0.0"`
- **THEN** 系统 SHALL 保持 server.listen.host 为字面量 `"${server_host}"`,不进行替换
@@ -151,6 +147,10 @@ targets 中的字符串值 SHALL 支持 `${key}` 语法引用变量。系统 SHA
- **WHEN** probes 配置 `execution.maxConcurrentChecks: "${max_checks}"` 且 variables 中定义 `max_checks: 5`
- **THEN** 系统 SHALL 保持 probes.execution.maxConcurrentChecks 为字面量 `"${max_checks}"`,不进行替换
#### Scenario: defaults 段被拒绝
- **WHEN** 配置文件声明顶层 `defaults`
- **THEN** 系统 SHALL 在契约校验阶段拒绝该未知字段,而不是尝试变量替换
### Requirement: 变量替换错误报告
变量替换阶段的错误 SHALL 作为 `ConfigValidationIssue` 输出code 为 `unresolved-variable`。错误信息 SHALL 包含 target 索引、target id、字段路径和变量名。

View File

@@ -0,0 +1,32 @@
## Purpose
定义 HTTP 类型拨测目标:通过 `type: http` 配置 HTTP/HTTPS 探测支持请求方法、headers、body、SSL 校验、重定向和响应体大小限制,捕获 HTTP 状态码、响应头、响应体和执行耗时,按 expect 规则校验并生成 matched 判定。
## Requirements
### Requirement: HTTP target 配置
系统 SHALL 支持 `type: http` 的 target 配置,通过 `http.url` 描述目标 HTTP 地址并通过可选字段控制请求方法、请求体、headers、SSL 校验、重定向和响应体大小限制。
#### Scenario: 解析最简 HTTP target
- **WHEN** YAML 中 target 配置 `type: http``http.url: "https://example.com"`
- **THEN** 系统 SHALL 将其解析为 HTTP checker并填充 `method=GET``maxBodyBytes=100MB``ignoreSSL=false``maxRedirects=0`、headers、body、interval、timeout、group 和 expect 配置
#### Scenario: HTTP target 缺少 url
- **WHEN** YAML 中 target 配置 `type: http` 但缺少 `http.url`
- **THEN** 系统 SHALL 以配置错误退出,并提示该 target 缺少 http.url 字段
#### Scenario: HTTP target 覆盖请求方法
- **WHEN** YAML 中某个 HTTP target 显式配置 `http.method: POST`
- **THEN** 该 target SHALL 使用自身 method 字段的值,而不是内置默认值 GET
#### Scenario: HTTP target 覆盖响应体大小限制
- **WHEN** YAML 中某个 HTTP target 显式配置 `http.maxBodyBytes`
- **THEN** 该 target SHALL 使用自身 maxBodyBytes 字段的值,而不是内置默认值 100MB
#### Scenario: HTTP target 覆盖 headers
- **WHEN** YAML 中某个 HTTP target 显式配置 `http.headers`
- **THEN** 该 target SHALL 使用自身 headers 字段的值,不再与规则文件级 defaults 合并
#### Scenario: HTTP 序列化展示摘要
- **WHEN** 系统同步 HTTP target 到 targets 表
- **THEN** `target` 展示摘要 SHALL 为 HTTP URL`config` JSON SHALL 包含 resolved 后的 url、method、headers、body、ignoreSSL、maxBodyBytes 和 maxRedirects

View File

@@ -24,25 +24,27 @@
- **THEN** 系统 SHALL 以配置错误退出并提示 `server` 中存在未知字段 `dataDir`
### Requirement: YAML 配置文件格式
系统 SHALL 支持通过 YAML 配置文件定义全部运行参数,包括 server 配置、probes 执行配置、可选的 variables 段、checker 默认值和 typed target 列表(含可选 group 字段。server 配置 SHALL 将 HTTP 监听参数放在 `server.listen` 分组,将本地数据目录和历史数据保留时长放在 `server.storage` 分组,将运行时日志配置放在 `server.logging` 分组。拨测全局执行策略 SHALL 放在 `probes.execution` 分组。target MUST 使用 `id` 字段作为唯一标识符MUST 使用 `type` 字段声明 checker 类型SHALL 支持可选的 `name` 字段作为展示名称元信息SHALL 支持可选的 `description` 字段作为目标说明。`name``description` 均 SHALL 允许省略或显式配置为 `null`;省略或显式 null 时解析结果 SHALL 保留为 null。HTTP 领域字段 MUST 放在 `http` 分组cmd 领域字段 MUST 放在 `cmd` 分组db 领域字段 MUST 放在 `db` 分组tcp 领域字段 MUST 放在 `tcp` 分组icmp 领域字段 MUST 放在 `icmp` 分组udp 领域字段 MUST 放在 `udp` 分组LLM 领域字段 MUST 放在 `llm` 分组。HTTP target 的 `http` 分组 SHALL 支持可选的 `ignoreSSL`(布尔值)和 `maxRedirects`非负整数字段。Db target 的 `db` 分组 SHALL 支持 `url`(必填)和 `query`可选字段。Tcp target 的 `tcp` 分组 SHALL 支持 `host`(必填)、`port`(必填)、`readBanner`(可选)、`bannerReadTimeout`(可选)和 `maxBannerBytes`可选字段。Icmp target 的 `icmp` 分组 SHALL 支持 `host`(必填)、`count`(可选,默认 3`packetSize`(可选,默认 56字段。Udp target 的 `udp` 分组 SHALL 支持 `host`(必填)、`port`(必填)、`payload`(可选,默认空字符串)、`encoding`(可选,默认 `text`)、`responseEncoding`(可选,默认 `text`)和 `maxResponseBytes`(可选,默认 4096字段。LLM target 的 `llm` 分组 SHALL 支持 `provider`(必填)、`url`(必填)、`model`(必填)、`prompt`(必填)、`mode`(可选,默认 `http`)、`key`(可选,默认空字符串)、`authToken`(可选)、`headers`(可选)、`ignoreSSL`(可选,默认 `false`)、`options`(可选)和 `providerOptions`(可选)字段。
`defaults.http` 分组 SHALL 仅支持 `headers`(可选)和 `maxBodyBytes`(可选)字段。`defaults.http` 分组 MUST NOT 支持 `method` 字段。`defaults.tcp` 分组 SHALL 仅支持 `bannerReadTimeout`(可选)和 `maxBannerBytes`(可选)字段。`defaults.icmp` 分组 SHALL 仅支持空对象。`defaults.udp` 分组 SHALL 仅支持 `encoding`(可选)、`responseEncoding`(可选)和 `maxResponseBytes`(可选)字段。`defaults.llm` 分组 SHALL 仅支持 `mode`(可选)、`headers`(可选)、`ignoreSSL`(可选)、`options`(可选)和 `providerOptions`(可选)字段。
系统 SHALL 支持通过 YAML 配置文件定义全部运行参数,包括 server 配置、probes 执行配置、可选的 variables 段和 typed target 列表(含可选 group 字段。server 配置 SHALL 将 HTTP 监听参数放在 `server.listen` 分组,将本地数据目录和历史数据保留时长放在 `server.storage` 分组,将运行时日志配置放在 `server.logging` 分组。拨测全局执行策略 SHALL 放在 `probes.execution` 分组。target MUST 使用 `id` 字段作为唯一标识符MUST 使用 `type` 字段声明 checker 类型SHALL 支持可选的 `name` 字段作为展示名称元信息SHALL 支持可选的 `description` 字段作为目标说明。`name``description` 均 SHALL 允许省略或显式配置为 `null`;省略或显式 null 时解析结果 SHALL 保留为 null。HTTP 领域字段 MUST 放在 `http` 分组cmd 领域字段 MUST 放在 `cmd` 分组db 领域字段 MUST 放在 `db` 分组tcp 领域字段 MUST 放在 `tcp` 分组icmp 领域字段 MUST 放在 `icmp` 分组udp 领域字段 MUST 放在 `udp` 分组LLM 领域字段 MUST 放在 `llm` 分组。HTTP target 的 `http` 分组 SHALL 支持可选的 `ignoreSSL`(布尔值)和 `maxRedirects`非负整数字段。Db target 的 `db` 分组 SHALL 支持 `url`(必填)和 `query`可选字段。Tcp target 的 `tcp` 分组 SHALL 支持 `host`(必填)、`port`(必填)、`readBanner`(可选)、`bannerReadTimeout`(可选)和 `maxBannerBytes`可选字段。Icmp target 的 `icmp` 分组 SHALL 支持 `host`(必填)、`count`(可选,默认 3`packetSize`(可选,默认 56字段。Udp target 的 `udp` 分组 SHALL 支持 `host`(必填)、`port`(必填)、`payload`(可选,默认空字符串)、`encoding`(可选,默认 `text`)、`responseEncoding`(可选,默认 `text`)和 `maxResponseBytes`(可选,默认 4096字段。LLM target 的 `llm` 分组 SHALL 支持 `provider`(必填)、`url`(必填)、`model`(必填)、`prompt`(必填)、`mode`(可选,默认 `http`)、`key`(可选,默认空字符串)、`authToken`(可选)、`headers`(可选)、`ignoreSSL`(可选,默认 `false`)、`options`(可选)和 `providerOptions`(可选)字段。顶层 `defaults` 不再是合法配置段。
#### Scenario: 完整配置文件解析
- **WHEN** 系统启动并读取包含 server.listen、server.storage、server.logging、probes.execution、variables、defaults、targets含 id、group 字段)的 YAML 配置文件
- **WHEN** 系统启动并读取包含 server.listen、server.storage、server.logging、probes.execution、variablestargets含 id、group 字段)的 YAML 配置文件
- **THEN** 系统 SHALL 正确解析所有字段并用于初始化服务、调度引擎和对应 checker runner
#### Scenario: defaults 配置段被拒绝
- **WHEN** 配置文件声明顶层 `defaults`
- **THEN** 系统 SHALL 以配置错误退出并提示存在未知字段 `defaults`
#### Scenario: 最简 HTTP 配置文件解析
- **WHEN** 系统读取只包含一个 `type: http` target`id``http.url`)的 YAML 配置文件(省略 server、probes、variables、defaults 和 expect
- **THEN** 系统 SHALL 使用内置默认值填充未指定的字段host=127.0.0.1, port=3000, dataDir=./data, interval=30s, timeout=10s, probes.execution.maxConcurrentChecks=20, server.storage.retention=7d, http.method=GET, http.maxBodyBytes=100MB, http.ignoreSSL=false, http.maxRedirects=0, group="default"),并保留 name=null、description=null
- **WHEN** 系统读取只包含一个 `type: http` target`id``http.url`)的 YAML 配置文件(省略 server、probes、variables 和 expect
- **THEN** 系统 SHALL 使用内置默认值填充未指定的字段host=127.0.0.1, port=3000, dataDir=./data, interval=30s, timeout=10s, probes.execution.maxConcurrentChecks=20, server.storage.retention=7d, http.method=GET, http.maxBodyBytes=100MB, http.ignoreSSL=false, http.maxRedirects=0, group=default并保留 name=null、description=null
#### Scenario: 最简 cmd 配置文件解析
- **WHEN** 系统读取只包含一个 `type: cmd` target`id``cmd.exec`)的 YAML 配置文件
- **THEN** 系统 SHALL 使用内置默认值填充未指定的字段interval=30s, timeout=10s, cmd.cwd 为配置文件所在目录, cmd.maxOutputBytes=100MB并保留 name=null、description=null
#### Scenario: per-target 配置覆盖全局默认值
- **WHEN** 某个 target 指定 interval、timeout 或对应领域分组中的默认字段
- **THEN** 该 target SHALL 使用其自身的值,不受 defaults 中对应字段影响
#### Scenario: per-target 配置覆盖内置默认值
- **WHEN** 某个 target 指定 interval、timeout 或对应领域分组中的可选字段
- **THEN** 该 target SHALL 使用其自身的值,不受对应内置默认值影响
#### Scenario: HTTP target 配置 ignoreSSL
- **WHEN** YAML 配置中 HTTP target 设置 `http.ignoreSSL: true`
@@ -58,43 +60,27 @@
#### Scenario: 最简 tcp 配置文件解析
- **WHEN** 系统读取只包含一个 `type: tcp` target`id``tcp.host``tcp.port`)的 YAML 配置文件
- **THEN** 系统 SHALL 使用内置默认值填充未指定的字段interval=30s, timeout=10s, group="default", tcp.readBanner=false, tcp.bannerReadTimeout=2000, tcp.maxBannerBytes=4096并保留 name=null、description=null
#### Scenario: defaults.tcp 配置 banner 默认值
- **WHEN** YAML 配置中 defaults.tcp 设置 `bannerReadTimeout``maxBannerBytes`
- **THEN** 未显式覆盖对应字段的 tcp target SHALL 使用 defaults.tcp 中的值
#### Scenario: defaults.http.method 触发校验错误
- **WHEN** 配置文件中出现 `defaults.http.method` 字段
- **THEN** 系统 SHALL 以配置错误退出,提示 defaults.http 中存在未知字段 method
- **THEN** 系统 SHALL 使用内置默认值填充未指定的字段interval=30s, timeout=10s, group=default, tcp.readBanner=false, tcp.bannerReadTimeout=2000, tcp.maxBannerBytes=4096并保留 name=null、description=null
#### Scenario: per-target http.method 仍然有效
- **WHEN** HTTP target 配置 `http.method: POST`
- **THEN** 系统 SHALL 使用 POST 作为该 target 的请求方法
#### Scenario: 未配置 http.method 使用内置默认值
- **WHEN** HTTP target 未配置 `http.method` 且 defaults.http 中无 method 字段
- **WHEN** HTTP target 未配置 `http.method`
- **THEN** 系统 SHALL 使用内置默认值 GET 作为该 target 的请求方法
#### Scenario: 最简 icmp 配置文件解析
- **WHEN** 系统读取只包含一个 `type: icmp` target`id``icmp.host`)的 YAML 配置文件
- **THEN** 系统 SHALL 使用内置默认值填充未指定的字段interval=30s, timeout=10s, group="default", icmp.count=3, icmp.packetSize=56并保留 name=null、description=null
- **THEN** 系统 SHALL 使用内置默认值填充未指定的字段interval=30s, timeout=10s, group=default, icmp.count=3, icmp.packetSize=56并保留 name=null、description=null
#### Scenario: 最简 udp 配置文件解析
- **WHEN** 系统读取只包含一个 `type: udp` target`id``udp.host``udp.port`)的 YAML 配置文件
- **THEN** 系统 SHALL 使用内置默认值填充未指定的字段interval=30s, timeout=10s, group="default", udp.payload="", udp.encoding="text", udp.responseEncoding="text", udp.maxResponseBytes=4096并保留 name=null、description=null
#### Scenario: defaults.udp 配置默认值
- **WHEN** YAML 配置中 defaults.udp 设置 `encoding``responseEncoding``maxResponseBytes`
- **THEN** 未显式覆盖对应字段的 udp target SHALL 使用 defaults.udp 中的值
- **THEN** 系统 SHALL 使用内置默认值填充未指定的字段interval=30s, timeout=10s, group=default, udp.payload=空字符串, udp.encoding=text, udp.responseEncoding=text, udp.maxResponseBytes=4096并保留 name=null、description=null
#### Scenario: 最简 llm 配置文件解析
- **WHEN** 系统读取只包含一个 `type: llm` target`id``llm.provider``llm.url``llm.model``llm.prompt`)的 YAML 配置文件
- **THEN** 系统 SHALL 使用内置默认值填充未指定字段interval=30s, timeout=10s, group="default", llm.mode="http", llm.key="", llm.ignoreSSL=false, llm.options.maxOutputTokens=16, llm.options.temperature=0并保留 name=null、description=null
#### Scenario: defaults.llm 配置默认值
- **WHEN** YAML 配置中 defaults.llm 设置 `mode``headers``ignoreSSL``options``providerOptions`
- **THEN** 未显式覆盖对应字段的 llm target SHALL 使用 defaults.llm 中的值
- **THEN** 系统 SHALL 使用内置默认值填充未指定字段interval=30s, timeout=10s, group=default, llm.mode=http, llm.key=空字符串, llm.ignoreSSL=false, llm.options.maxOutputTokens=16, llm.options.temperature=0并保留 name=null、description=null
### Requirement: CLI 参数
系统 SHALL 通过单一命令行参数接受 YAML 配置文件路径。
@@ -126,6 +112,10 @@
- **WHEN** YAML 中某个 target 缺少 id 或 type 字段
- **THEN** 系统 SHALL 以错误退出,提示哪个 target 缺少哪个字段
#### Scenario: 顶层 defaults 字段非法
- **WHEN** YAML 配置文件声明顶层 `defaults`
- **THEN** 系统 SHALL 以配置错误退出,提示 `defaults` 是未知字段
#### Scenario: HTTP target 缺少 url
- **WHEN** YAML 中某个 target 配置 `type: http` 但缺少 `http.url`
- **THEN** 系统 SHALL 以错误退出,提示该 target 缺少 http.url 字段
@@ -203,7 +193,7 @@
- **THEN** 系统 SHALL 以错误退出,提示该 target 的 http.body 必须为字符串
#### Scenario: maxBodyBytes 数字非法
- **WHEN** YAML 中某个 HTTP target 的 `http.maxBodyBytes` 或 defaults.http.maxBodyBytes 是负数、非整数或非安全整数
- **WHEN** YAML 中某个 HTTP target 的 `http.maxBodyBytes` 是负数、非整数或非安全整数
- **THEN** 系统 SHALL 以错误退出,提示 maxBodyBytes 必须为非负安全整数字节数或合法 size 字符串
#### Scenario: status 模式非法
@@ -291,7 +281,7 @@
- **THEN** 系统 SHALL 以错误退出,提示未知字段所在路径
#### Scenario: 动态 headers 字段允许
- **WHEN** YAML 中 `http.headers``defaults.http.headers``expect.headers` 包含任意 header 名称,且对应值符合契约
- **WHEN** YAML 中 `http.headers``expect.headers` 包含任意 header 名称,且对应值符合契约
- **THEN** 系统 SHALL 接受这些动态 header 名称
#### Scenario: 动态 env 字段允许
@@ -312,7 +302,7 @@
#### Scenario: 导出配置 JSON Schema
- **WHEN** 仓库生成或检查配置契约
- **THEN** 根目录 SHALL 存在 draft-07 `probe-config.schema.json`,且其内容 SHALL 与当前公共 fragments 和已注册 checker fragments 组装出的完整 schema 一致(包含 variables 段和 target 的 id/name 字段)。所有 `RawValueExpectation` 字段的 schema SHALL 声明为 `anyOf: [primitiveValue, matcherObject]` 联合类型,`RawKeyedExpectations` 的 dynamic value schema SHALL 复用 `RawValueExpectation`
- **THEN** 根目录 SHALL 存在 draft-07 `probe-config.schema.json`,且其内容 SHALL 与当前公共 fragments 和已注册 checker fragments 组装出的完整 schema 一致(包含 variables 段和 target 的 id/name 字段,且不包含顶层 defaults)。所有 `RawValueExpectation` 字段的 schema SHALL 声明为 `anyOf: [primitiveValue, matcherObject]` 联合类型,`RawKeyedExpectations` 的 dynamic value schema SHALL 复用 `RawValueExpectation`
#### Scenario: JSON Schema RawValueExpectation 接受原始值
- **WHEN** 使用 JSON Schema 校验配置文件中 RawValueExpectation 字段值为数字 `5000`
@@ -431,7 +421,7 @@
- **THEN** 系统 SHALL 接受该配置并在运行期使用完整执行耗时进行 matcher 校验
#### Scenario: 动态 headers 字段允许
- **WHEN** YAML 中 `http.headers``defaults.http.headers``llm.headers``defaults.llm.headers``expect.headers` 包含任意 header 名称,且对应值符合契约
- **WHEN** YAML 中 `http.headers``llm.headers``expect.headers` 包含任意 header 名称,且对应值符合契约
- **THEN** 系统 SHALL 接受这些动态 header 名称
#### Scenario: ContentExpectations 字段必须为数组
@@ -546,11 +536,11 @@
- **THEN** 系统 SHALL 以配置错误退出,提示 tcp.readBanner 必须为布尔值
#### Scenario: tcp bannerReadTimeout 非法
- **WHEN** YAML 中 tcp target 或 defaults.tcp `bannerReadTimeout` 不是非负有限数字
- **WHEN** YAML 中 tcp target 的 `bannerReadTimeout` 不是非负有限数字
- **THEN** 系统 SHALL 以配置错误退出,提示 bannerReadTimeout 格式错误
#### Scenario: tcp maxBannerBytes 非法
- **WHEN** YAML 中 tcp target 或 defaults.tcp `maxBannerBytes` 不是合法 size 值
- **WHEN** YAML 中 tcp target 的 `maxBannerBytes` 不是合法 size 值
- **THEN** 系统 SHALL 以配置错误退出,提示 maxBannerBytes 格式错误
#### Scenario: tcp expect connected 类型非法
@@ -569,12 +559,8 @@
- **WHEN** YAML 中 tcp target 的 `tcp` 分组包含 `tls: true` 等未知字段
- **THEN** 系统 SHALL 以配置错误退出,提示 tcp 分组包含未知字段
#### Scenario: defaults.tcp 未知字段失败
- **WHEN** YAML 中 defaults.tcp 包含 `host` 或其他非默认字段
- **THEN** 系统 SHALL 以配置错误退出,提示 defaults.tcp 包含未知字段
### Requirement: LLM 配置校验
系统 SHALL 在启动期对 llm checker 的配置契约和语义执行严格校验。LLM target 的 `llm` 分组 SHALL 只允许 `provider``url``model``prompt``mode``key``authToken``headers``ignoreSSL``options``providerOptions` 字段。`defaults.llm` 分组 SHALL 只允许 `mode``headers``ignoreSSL``options``providerOptions` 字段。LLM expect SHALL 只允许 `status``headers``output``finishReason``rawFinishReason``usage``stream``durationMs` 字段。`expect.output` MUST 为 `RawContentExpectations` 数组。`expect.finishReason``expect.rawFinishReason``expect.usage.*``expect.stream.firstTokenMs``expect.durationMs` SHALL 使用 `RawValueExpectation`。未知字段、非法 provider、非法 URL、非法 mode、非法认证组合、非法 options、非法 output expectation 和 `mode: http` 下配置 `expect.stream` MUST 导致启动期配置错误。语义校验 MUST NOT 修改 Raw llm expect 输入。
系统 SHALL 在启动期对 llm checker 的配置契约和语义执行严格校验。LLM target 的 `llm` 分组 SHALL 只允许 `provider``url``model``prompt``mode``key``authToken``headers``ignoreSSL``options``providerOptions` 字段。LLM expect SHALL 只允许 `status``headers``output``finishReason``rawFinishReason``usage``stream``durationMs` 字段。`expect.output` MUST 为 `RawContentExpectations` 数组。`expect.finishReason``expect.rawFinishReason``expect.usage.*``expect.stream.firstTokenMs``expect.durationMs` SHALL 使用 `RawValueExpectation`。未知字段、非法 provider、非法 URL、非法 mode、非法认证组合、非法 options、非法 output expectation 和 `mode: http` 下配置 `expect.stream` MUST 导致启动期配置错误。语义校验 MUST NOT 修改 Raw llm expect 输入。
#### Scenario: llm provider 非法
- **WHEN** YAML 中 llm target 的 `llm.provider` 不是 `openai``openai-responses``anthropic`
@@ -593,15 +579,15 @@
- **THEN** 系统 SHALL 以配置错误退出,提示 llm.prompt 必须为非空字符串
#### Scenario: llm mode 非法
- **WHEN** YAML 中 llm target 或 defaults.llm `mode` 不是 `http``stream`
- **WHEN** YAML 中 llm target 的 `mode` 不是 `http``stream`
- **THEN** 系统 SHALL 以配置错误退出,提示 llm.mode 不合法
#### Scenario: llm headers 类型非法
- **WHEN** YAML 中 llm target 或 defaults.llm `headers` 不是对象,或任一 header 值不是字符串
- **WHEN** YAML 中 llm target 的 `headers` 不是对象,或任一 header 值不是字符串
- **THEN** 系统 SHALL 以配置错误退出,提示 llm.headers 格式错误
#### Scenario: llm ignoreSSL 类型非法
- **WHEN** YAML 中 llm target 或 defaults.llm `ignoreSSL` 不是布尔值
- **WHEN** YAML 中 llm target 的 `ignoreSSL` 不是布尔值
- **THEN** 系统 SHALL 以配置错误退出,提示 llm.ignoreSSL 必须为布尔值
#### Scenario: llm authToken provider 非法
@@ -613,11 +599,11 @@
- **THEN** 系统 SHALL 以配置错误退出,提示 key 与 authToken 不能同时配置
#### Scenario: llm options 非法
- **WHEN** YAML 中 llm target 或 defaults.llm `options.maxOutputTokens` 不是正整数,`options.temperature`/`topP`/`topK`/`presencePenalty`/`frequencyPenalty`/`seed` 类型不合法,或 `options.stopSequences` 不是字符串数组
- **WHEN** YAML 中 llm target 的 `options.maxOutputTokens` 不是正整数,`options.temperature`/`topP`/`topK`/`presencePenalty`/`frequencyPenalty`/`seed` 类型不合法,或 `options.stopSequences` 不是字符串数组
- **THEN** 系统 SHALL 以配置错误退出,提示 llm.options 格式错误
#### Scenario: llm providerOptions 非法
- **WHEN** YAML 中 llm target 或 defaults.llm `providerOptions` 不是 JSON object
- **WHEN** YAML 中 llm target 的 `providerOptions` 不是 JSON object
- **THEN** 系统 SHALL 以配置错误退出,提示 llm.providerOptions 格式错误
#### Scenario: llm 禁止字段失败