- 合并 20+ 细粒度 spec 为粗粒度主题规范:dashboard、data-store、probe-engine、probe-api、probe-config 等 - 删除完全冗余规范:data-retention(被 probe-engine+data-store 覆盖)、backend-code-quality(DEVELOPMENT.md 已记录) - 补充 http-checker 规范至完整标准(配置+执行+expect+校验+observation),匹配代码 440 行实现 - 清理 tcp/udp/llm checker 规范中已废弃 defaults 配置段的残留 Scenario - 清理 checker-cohesion-structure 中的实现路径引用(src/server/...) - 统一所有 spec 格式(## Purpose 开头,去除 # Capability/Title 形式) - 更新 prompt-spec-review.md 审查提示文档
159 lines
8.7 KiB
Markdown
159 lines
8.7 KiB
Markdown
## Purpose
|
||
|
||
定义 CheckResult 的 observation 数据模型、各 checker 类型 observation 结构、截断策略、序列化规则和 detail 动态构造机制。
|
||
|
||
## Requirements
|
||
|
||
### Requirement: Observation 数据模型
|
||
CheckResult SHALL 包含 `observation: Record<string, unknown> | null` 字段,用于承载 checker 执行过程中收集的结构化观测数据。observation 为 null 表示执行过程中无法形成有意义的领域观测数据(如进程 spawn 失败、内部异常、请求在拿到响应前失败且无可记录元数据等场景)。各 checker SHALL 自行定义 observation 的内部结构,不做跨 checker 类型的统一约束。
|
||
|
||
#### Scenario: 正常执行返回 observation
|
||
- **WHEN** checker 执行成功、expect 断言失败或产生可收集上下文的负向结果
|
||
- **THEN** CheckResult.observation SHALL 包含该 checker 类型定义的完整观测数据
|
||
|
||
#### Scenario: 异常执行返回 null observation
|
||
- **WHEN** checker 执行过程中发生无法收集领域观测数据的异常
|
||
- **THEN** CheckResult.observation SHALL 为 null
|
||
|
||
### Requirement: HTTP Checker Observation
|
||
HTTP checker 的 observation SHALL 包含 statusCode(number)、headers(Record<string, string>,截断)、bodyPreview(string | null,截断)、contentType(string | null)、contentLength(number | null)。
|
||
|
||
#### Scenario: 正常 HTTP 响应
|
||
- **WHEN** HTTP 请求成功返回
|
||
- **THEN** observation SHALL 包含响应状态码、截断后的响应 headers、响应体预览、Content-Type 和 Content-Length,即使未配置 body expect 也 SHALL 采集 bodyPreview
|
||
|
||
#### Scenario: HTTP 请求失败
|
||
- **WHEN** HTTP 请求因网络错误或超时失败
|
||
- **THEN** observation SHALL 为 null
|
||
|
||
### Requirement: TCP Checker Observation
|
||
TCP checker 的 observation SHALL 包含 connected(boolean)、connectTimeMs(number | null)、banner(string | null,截断)、error(string | null)。
|
||
|
||
#### Scenario: TCP 连接成功且读取 banner
|
||
- **WHEN** TCP 连接成功并读取到 banner
|
||
- **THEN** observation SHALL 包含 connected=true、连接耗时、截断后的 banner 内容
|
||
|
||
#### Scenario: TCP 连接失败
|
||
- **WHEN** TCP 连接失败
|
||
- **THEN** observation SHALL 包含 connected=false 和错误信息
|
||
|
||
### Requirement: UDP Checker Observation
|
||
UDP checker 的 observation SHALL 包含 responded(boolean)、durationMs(number)、responseSize(number | null)、responsePreview(string | null,截断)、sourceAddress(string | null)、sourcePort(number | null)、error(string | null)。durationMs 用于 API 序列化层生成包含耗时的 UDP detail 摘要。
|
||
|
||
#### Scenario: UDP 收到响应
|
||
- **WHEN** UDP 发送数据后收到响应
|
||
- **THEN** observation SHALL 包含 responded=true、响应大小、截断后的响应预览、来源地址和端口
|
||
|
||
#### Scenario: UDP 未收到响应
|
||
- **WHEN** UDP 发送数据后超时未收到响应
|
||
- **THEN** observation SHALL 包含 responded=false
|
||
|
||
### Requirement: ICMP Checker Observation
|
||
ICMP checker 的 observation SHALL 包含 alive(boolean)、transmitted(number)、received(number)、packetLoss(number)、avgLatencyMs(number | null)、maxLatencyMs(number | null)、minLatencyMs(number | null)、error(string | null)。
|
||
|
||
#### Scenario: ICMP 正常返回统计
|
||
- **WHEN** ping 命令成功执行并解析出统计数据
|
||
- **THEN** observation SHALL 包含完整的 ICMPStats 字段
|
||
|
||
#### Scenario: ICMP 命令失败
|
||
- **WHEN** ping 命令未找到或超时
|
||
- **THEN** observation SHALL 为 null 或包含 error 字段
|
||
|
||
### Requirement: DB Checker Observation
|
||
DB checker 的 observation SHALL 包含 connected(boolean)、rowCount(number | null)、rowsPreview(unknown[] | null,截断前 N 行)、error(string | null)。
|
||
|
||
#### Scenario: 数据库查询成功
|
||
- **WHEN** 数据库连接和查询成功
|
||
- **THEN** observation SHALL 包含 connected=true、行数、截断后的行预览
|
||
|
||
#### Scenario: 仅探活无查询
|
||
- **WHEN** 数据库配置仅探活连接(无 query)
|
||
- **THEN** observation SHALL 包含 connected=true,rowCount 和 rowsPreview 为 null
|
||
|
||
### Requirement: CMD Checker Observation
|
||
CMD checker 的 observation SHALL 包含 exitCode(number | null)、stdoutPreview(string | null,截断)、stderrPreview(string | null,截断)、error(string | null)。
|
||
|
||
#### Scenario: 命令正常执行
|
||
- **WHEN** 命令执行完成
|
||
- **THEN** observation SHALL 包含退出码、截断后的 stdout 和 stderr 预览
|
||
|
||
#### Scenario: 命令 spawn 失败
|
||
- **WHEN** 命令进程无法启动
|
||
- **THEN** observation SHALL 为 null
|
||
|
||
### Requirement: LLM Checker Observation
|
||
LLM checker SHALL 保留执行期 `LlmCheckObservation.outputText` 完整文本用于 expect 校验,并从执行期 observation 派生持久化 observation。持久化 observation SHALL 包含 provider(string)、mode(string)、model(string)、http({ status, statusText, headers } | null,headers 截断)、finishReason(string | null)、rawFinishReason(string | null)、outputPreview(string | null,截断)、outputLength(number | null)、usage({ inputTokens, outputTokens, totalTokens } | null)、stream({ completed, firstTokenMs } | null)、warnings(string[])。
|
||
|
||
#### Scenario: LLM HTTP 模式成功
|
||
- **WHEN** LLM 以 HTTP 模式成功执行
|
||
- **THEN** observation SHALL 包含 provider、mode、model、HTTP 元数据、finish 原因、截断后的输出预览、完整输出长度和 token 用量
|
||
|
||
#### Scenario: LLM Stream 模式成功
|
||
- **WHEN** LLM 以 stream 模式成功执行
|
||
- **THEN** observation SHALL 额外包含 stream 观测数据(completed、firstTokenMs)
|
||
|
||
### Requirement: Observation 截断策略
|
||
各 checker SHALL 对 observation 中的大文本和集合字段执行截断,防止存储膨胀。
|
||
|
||
#### Scenario: HTTP body 截断
|
||
- **WHEN** HTTP 响应体超过 1024 字符
|
||
- **THEN** bodyPreview SHALL 截断为前 1024 字符
|
||
|
||
#### Scenario: HTTP headers 截断
|
||
- **WHEN** HTTP 响应 headers 超过 20 个
|
||
- **THEN** headers SHALL 仅保留前 20 个
|
||
|
||
#### Scenario: TCP banner 截断
|
||
- **WHEN** TCP banner 内容超过 256 字符
|
||
- **THEN** banner SHALL 截断为前 256 字符
|
||
|
||
#### Scenario: UDP response 截断
|
||
- **WHEN** UDP 响应预览超过 512 字符
|
||
- **THEN** responsePreview SHALL 截断为前 512 字符
|
||
|
||
#### Scenario: DB rows 截断
|
||
- **WHEN** 查询返回超过 5 行
|
||
- **THEN** rowsPreview SHALL 仅保留前 5 行
|
||
|
||
#### Scenario: CMD stdout/stderr 截断
|
||
- **WHEN** stdout 或 stderr 超过 1024 字符
|
||
- **THEN** 对应 Preview 字段 SHALL 截断为前 1024 字符
|
||
|
||
#### Scenario: LLM output 截断
|
||
- **WHEN** LLM 输出文本超过 512 字符
|
||
- **THEN** outputPreview SHALL 截断为前 512 字符
|
||
|
||
#### Scenario: LLM headers 截断
|
||
- **WHEN** LLM 响应 headers 超过 20 个
|
||
- **THEN** headers SHALL 仅保留前 20 个
|
||
|
||
### Requirement: Observation 序列化规则
|
||
observation SHALL 使用 JSON.stringify 序列化为 TEXT 格式存入 SQLite,使用 JSON.parse 反序列化读出。不引入额外的序列化依赖。
|
||
|
||
#### Scenario: 写入 observation
|
||
- **WHEN** 存储 CheckResult 到数据库
|
||
- **THEN** observation 字段 SHALL 使用 JSON.stringify 序列化后存入 TEXT 列;observation 为 null 时 SHALL 存入 SQL NULL
|
||
|
||
#### Scenario: 读取 observation
|
||
- **WHEN** 从数据库读取 CheckResult
|
||
- **THEN** observation 字段 SHALL 使用 JSON.parse 反序列化;SQL NULL 值 SHALL 映射为 null
|
||
|
||
#### Scenario: 使用 SQLite CLI 直接查看
|
||
- **WHEN** 开发者使用 sqlite3 CLI 工具查看 check_results 表
|
||
- **THEN** observation 列 SHALL 为人可读的 JSON 文本
|
||
|
||
### Requirement: Detail 动态构造
|
||
CheckResult SHALL 包含 `detail: string | null` 字段(替代原 statusDetail),该字段 SHALL 不持久化到数据库,而是在 API 序列化层根据 target type 从 observation 动态构造。每个 checker SHALL 提供 `buildDetail(observation)` 方法,定义该 checker 类型的人可读摘要格式。
|
||
|
||
#### Scenario: API 返回 detail 字段
|
||
- **WHEN** API 序列化 CheckResult 返回给前端
|
||
- **THEN** 系统 SHALL 根据 target type 调用对应 checker 的 buildDetail 方法,从 observation 动态生成 detail 字段
|
||
|
||
#### Scenario: observation 为 null 时
|
||
- **WHEN** observation 为 null
|
||
- **THEN** detail SHALL 为 null
|
||
|
||
#### Scenario: 各 checker 的 detail 格式
|
||
- **WHEN** 各 checker 的 buildDetail 被调用
|
||
- **THEN** HTTP SHALL 返回 `"HTTP {statusCode}"` 格式;TCP SHALL 返回连接状态和 banner 摘要;UDP SHALL 返回响应状态和大小摘要;Ping SHALL 返回存活状态、平均延迟和丢包率摘要;ICMP SHALL 返回存活状态、平均延迟和丢包率摘要;DB SHALL 返回连接状态或行数摘要;CMD SHALL 返回 `"exitCode={N}"` 格式;LLM SHALL 返回 provider、mode、状态码、finish 原因、输出长度和 token 用量摘要
|