# 校验规则

本文档说明 `expect` 规则、状态判定、failure、observation 和各 checker 的快速失败顺序。

适用场景：编写 `expect`、理解 UP/DOWN、排查 mismatch/error、查看返回结果中的 `failure` 和 `observation`。

`expect` 描述拨测结果必须满足的条件。不同 checker 暴露不同字段，但共享三类基础断言模型：`ValueMatcher`、`ContentExpectations` 和 `KeyedExpectations`。

## 状态判定

DiAL 使用单层状态模型。

| 状态   | 含义                                     |
| ------ | ---------------------------------------- |
| `UP`   | 拨测结果符合 `expect` 规则               |
| `DOWN` | 拨测结果不符合 `expect` 规则，或执行失败 |

执行失败（网络错误、超时、进程崩溃）和 expect 不匹配都统一为 `DOWN`，通过 `failure.kind` 区分原因。

| `failure.kind` | 含义                                     |
| -------------- | ---------------------------------------- |
| `error`        | 网络、超时、进程、协议解析或内部执行错误 |
| `mismatch`     | 拨测完成，但结果不满足 expect            |

## API 结果字段

API 返回的检查结果包含 `detail` 和 `observation`。

| 字段          | 说明                                                         |
| ------------- | ------------------------------------------------------------ |
| `detail`      | 后端按 checker 类型从结构化 observation 动态生成的人可读摘要 |
| `observation` | 保存该次检查的结构化观测数据                                 |
| `failure`     | 保存首个错误或不匹配原因                                     |
| `matched`     | 是否符合 expect                                              |
| `durationMs`  | 本次检查耗时                                                 |
| `timestamp`   | 本次检查时间                                                 |

`detail` 不写入 SQLite。存储层仅持久化 `observation` JSON、`failure` JSON、匹配状态、耗时和时间戳。

## observation 示例

不同 checker 的 observation 字段不同，常见信息包括：

| Checker | observation 内容示例                                               |
| ------- | ------------------------------------------------------------------ |
| HTTP    | 状态码、响应头、按需读取的 body 预览                               |
| Cmd     | exit code、stdout/stderr 预览                                      |
| TCP     | 连接结果、banner 摘要                                              |
| UDP     | 响应内容、来源地址、响应大小                                       |
| ICMP    | 存活结果、丢包率、平均延迟、最大延迟                               |
| DNS     | RCODE、记录值、TTL、flags、CNAME 链                                |
| LLM     | HTTP 状态、模型输出、finish reason、token usage、流式首 token 时间 |
| WS      | 连接结果、连接耗时、握手头、消息内容、消息大小                     |

Dashboard 基于存储的检查结果计算实时状态、可用率、耗时趋势、P95、状态条和故障段等指标。指标语义由后端应用层实现，SQLite 主要负责存储、筛选、排序、分页和基础聚合。

## ContentExpectations

`body`、`stdout`、`stderr`、`banner`、`response`、`output`、`result`、`message` 等返回内容字段均使用数组。

| 规则       | 说明                                                   |
| ---------- | ------------------------------------------------------ |
| `contains` | 内容包含指定文本                                       |
| `regex`    | 正则匹配，启动期会拒绝存在 ReDoS 风险的模式            |
| `json`     | JSONPath 提取值比较，`path` 必填                       |
| `css`      | CSS 选择器提取 HTML 元素，`selector` 必填，`attr` 可选 |
| `xpath`    | XPath 提取 XML/HTML 节点，`path` 必填                  |

示例：

```yaml
expect:
  body:
    - contains: "ok"
    - json:
        path: "$.status"
        equals: "ready"
```

ContentExpectations 数组按顺序快速失败。数组项可以是直接 matcher，也可以是 `json`、`css`、`xpath` 提取器规则。一条规则不能混用直接 matcher 和 extractor，多个 extractor 也不能共存。Extractor 未配置 matcher 时等价于 `exists: true`。

## ValueMatcher

`ValueMatcher` 用于单个标量值、数字指标和字符串元数据。

| 字段       | 说明                            |
| ---------- | ------------------------------- |
| `equals`   | 精确匹配，支持 JSON 深度相等    |
| `contains` | 字符串包含                      |
| `regex`    | 正则匹配，固定使用无 flags 正则 |
| `empty`    | 判断是否为空                    |
| `exists`   | 判断是否存在                    |
| `gte`      | 大于等于                        |
| `lte`      | 小于等于                        |
| `gt`       | 大于                            |
| `lt`       | 小于                            |

一个 matcher 对象内多个字段为 AND 语义。`exists: false` 不能和其他 matcher 组合。

ValueMatcher expect 字段可直接写 string、number、boolean 或 null，等价于 `{ equals: value }`。数组和对象必须显式写成 `{ equals: ... }`。

```yaml
expect:
  durationMs:
    lte: 5000
  finishReason: "stop"
```

## KeyedExpectations

`headers`、DB `rows[]` 中的列值等动态键值对象使用 `KeyedExpectations`。每个键的值支持 `ValueMatcher` 的全部字段，字面量值自动等价于 `{ equals: value }`。

```yaml
expect:
  headers:
    Content-Type:
      contains: "application/json"
```

## 大小和时长格式

| 类型 | 示例                             |
| ---- | -------------------------------- |
| 大小 | `4KB`、`10MB`、`1GB`、直接数字   |
| 时长 | `500ms`、`30s`、`5m`、`2h`、`7d` |

`maxBodyBytes`、`maxOutputBytes`、`maxResponseBytes`、`maxBannerBytes` 等大小字段支持 `KB`、`MB`、`GB` 单位。

## 快速失败顺序

| Checker    | 顺序                                                                                                                                                                             |
| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| HTTP       | `status -> headers -> body -> durationMs`                                                                                                                                        |
| Cmd        | `exitCode -> durationMs -> stdout -> stderr`                                                                                                                                     |
| DB         | `durationMs -> rowCount -> rows -> result`                                                                                                                                       |
| TCP        | `connected -> banner -> durationMs`                                                                                                                                              |
| UDP        | `responded -> responseSize -> response -> sourceHost -> sourcePort -> durationMs`                                                                                                |
| ICMP       | `alive -> packetLossPercent -> avgLatencyMs -> maxLatencyMs -> durationMs`                                                                                                       |
| DNS system | `values -> valueCount -> durationMs`                                                                                                                                             |
| DNS server | `responded -> rcode -> values -> valueCount -> answerCount -> ttlMin -> ttlMax -> authoritative -> recursionAvailable -> truncated -> authenticatedData -> result -> durationMs` |
| LLM http   | `status -> headers -> output -> finishReason -> rawFinishReason -> usage -> durationMs`                                                                                          |
| LLM stream | `status -> headers -> stream.completed -> stream.firstTokenMs -> output -> finishReason -> rawFinishReason -> usage -> durationMs`                                               |
| WS         | `connected -> handshakeHeaders -> message -> connectTimeMs -> durationMs`                                                                                                        |

## JSON Schema

仓库根目录导出 `probe-config.schema.json`。在 YAML 文件顶部添加以下注释可在编辑器中获得提示和校验：

```yaml
# yaml-language-server: $schema=./probe-config.schema.json
```

## 已移除字段

旧字段 `maxDurationMs`、`maxPacketLoss`、`maxAvgLatencyMs`、`maxMaxLatencyMs` 和旧正则字段 `match` 已移除，请分别改用 `durationMs`、ICMP matcher 字段和 `regex`。

非法配置会阻止启动并输出错误信息。除动态键值表（`headers`、`env`、`variables`）外，未知字段会导致启动失败，请使用 YAML 注释表达说明。

## 更新触发条件

修改 expect 断言模型、状态判定、failure 字段、observation 字段、快速失败顺序或已移除字段说明时，必须更新本文档。
