1
0

docs: 归档 checker 内聚化重构变更,同步 delta specs 到主规范

- 归档 refactor-checker-coherence 变更至 archive/2026-05-13-refactor-checker-cohesion/
- 新增主规范 checker-cohesion-structure(12 条需求)
- 更新主规范 checker-runner-abstraction(新增 base interface 类型相关场景)
This commit is contained in:
2026-05-13 15:02:59 +08:00
parent bb6b2bc20b
commit 26f0bfe104
7 changed files with 30 additions and 395 deletions

View File

@@ -1,2 +0,0 @@
schema: spec-driven
created: 2026-05-13

View File

@@ -1,232 +0,0 @@
## Context
当前 `src/server/checker/` 的代码组织存在内聚性不足的问题:
- 顶层 `types.ts` 混合了所有 checker 的类型定义(`HttpTargetConfig``ResolvedHttpTarget``CommandExpectConfig` 等),形成硬编码联合类型 `ResolvedTarget = ResolvedHttpTarget | ResolvedCommandTarget`
- `runner/shared/` 中混合了真正跨 checker 共享的断言基础设施和仅单个 checker 使用的模块
- `config-contract/` 命名不直观,内部 `schema.ts` 与目录名语义重叠
- 新增 checker 需要修改 3-4 个文件(顶层 types、联合类型、注册入口、可能还有 shared
项目核心是 checker 系统,需要让每个 checker 的代码尽可能内聚,降低新增和维护成本。
## Goals / Non-Goals
**Goals:**
- 新增 checker 只需:创建一个目录 + 在注册列表加一行 import
- 每个 checker 目录包含完整的类型、schema、校验、执行逻辑
- 共享断言基础设施有明确的物理位置和语义命名
- 依赖方向清晰checker → expect/断言基础设施、schema/fragmentsschema 片段、utils工具函数
**Non-Goals:**
- 不改变任何运行时行为、配置文件格式、API 接口
- 不引入自动目录扫描机制(保持显式注册)
- 不改变测试覆盖范围(只更新 import 路径)
## Decisions
### Decision 1: ResolvedTarget 和 TargetConfig 改为 base interface
**选择**: 删除硬编码联合类型,改为 base interface + 各 checker 内部 narrow
**理由**: engine、store、config-loader 从来不关心具体 checker 类型——它们只用 base 字段type、name、group、intervalMs、timeoutMs+ 通过 registry dispatch。各 checker 的 execute/resolve/serialize 内部第一行就是 `as ResolvedXxxTarget`,联合类型对它们没有实际约束价值。
同理,`DefaultsConfig` 当前也是硬编码联合(`command?: CommandDefaultsConfig; http?: HttpDefaultsConfig`),新增 checker 仍需改这个 interface。改为宽松 base 形式:
```typescript
export interface DefaultsConfig {
interval?: string;
timeout?: string;
[checkerKey: string]: unknown;
}
```
各 checker 的 `validate()` 方法接收 `DefaultsConfig` 后自行 narrow`defaults["http"] as HttpDefaultsConfig`)。`CheckerValidationInput``ResolveContext` 中的 `defaults` 字段类型保持为 `DefaultsConfig`,对外部透明。
**替代方案**: 保留联合但用 barrel 自动聚合——仍需改文件,不够彻底。
**具体设计**:
```typescript
// checker/types.ts — 公共 base
export interface ResolvedTargetBase {
type: string;
name: string;
group: string;
intervalMs: number;
timeoutMs: number;
expect?: unknown;
}
export interface RawTargetConfig {
type: string;
name: string;
group?: string;
interval?: string;
timeout?: string;
expect?: unknown;
[configKey: string]: unknown;
}
// runner/http/types.ts — HTTP 专属
export interface ResolvedHttpTarget extends ResolvedTargetBase {
type: "http";
http: ResolvedHttpConfig;
expect?: HttpExpectConfig;
}
```
### Decision 2: 显式列表注册
**选择**: `runner/index.ts` 维护 import 列表,新增 checker 加一行
**理由**: Bun bundler 和 tree-shaking 依赖静态 import运行时扫描目录引入不确定性临时文件、.bak 等);一行 import 的成本几乎为零。
**具体设计**:
```typescript
// runner/index.ts
import { CheckerRegistry } from "./registry";
import { HttpChecker } from "./http";
import { CommandChecker } from "./command";
const checkers = [
new HttpChecker(),
new CommandChecker(),
];
export function createDefaultCheckerRegistry(): CheckerRegistry {
const registry = new CheckerRegistry();
for (const checker of checkers) {
registry.register(checker);
}
return registry;
}
export const checkerRegistry = createDefaultCheckerRegistry();
```
### Decision 3: 各 checker 的 index.ts 仅做 re-export
**选择**: class 定义在 `execute.ts``index.ts` 只做 `export { HttpChecker } from "./execute"`
**理由**: 保持单一职责——`execute.ts` 专注执行逻辑,`index.ts` 是对外入口。
### Decision 4: runner/shared/ 拆分策略
**选择**: 按实际使用情况拆分为三个去向
| 原文件 | 去向 | 理由 |
|--------|------|------|
| `operator.ts` | `checker/expect/operator.ts` | 所有 checker 的 expect 最终都走这里 |
| `duration.ts` | `checker/expect/duration.ts` | 任何 checker 都可能有 maxDurationMs |
| `failure.ts` | `checker/expect/failure.ts` | 构造 CheckFailure所有 checker 共用 |
| `validate.ts``validateOperatorObject` | `checker/expect/validate-operator.ts` | 通用 operator 校验 |
| `body.ts` | `runner/http/body.ts` | 仅 HTTP 使用 |
| `text.ts` | `runner/command/text.ts` | 仅 Command 使用 |
| `validate.ts``validateBodyRules` 等 | `runner/http/validate.ts` | HTTP 专属校验 |
| `validate.ts``validateTextRules` | `runner/command/validate.ts` | Command 专属校验 |
**理由**: `expect/` 命名比 `shared/` 更能表达语义——这些是断言系统的基础设施。仅单个 checker 使用的模块搬入对应目录实现真正内聚。
### Decision 5: config-contract/ 重命名为 schema/
**选择**: 目录改名 `schema/`,内部 `schema.ts` 改名 `builder.ts`
**理由**: "config-contract" 过于抽象,`schema/` 直接表达"这里是 schema 定义和校验"。内部 `schema.ts` 与目录名冲突,改为 `builder.ts` 表达"从 registry 动态构建整体 schema"的职责。
### Decision 6: 纯工具函数归入 utils.ts
**选择**: `size.ts``parseSize``config-loader.ts` 中的 `parseDuration` 合并到 `checker/utils.ts`
**理由**: 这些是无状态的纯解析函数,不属于任何特定领域。统一放置便于复用。
### Decision 7: 文件重命名
| 原名 | 新名 | 理由 |
|------|------|------|
| 各 checker 的 `runner.ts` | `execute.ts` | 避免和目录名 `runner/` 混淆 |
| 各 checker 的 `contract.ts` | `schema.ts` | 和顶层 `schema/` 目录呼应,统一术语 |
## 最终目录结构
```
src/server/checker/
├── index.ts
├── engine.ts
├── store.ts
├── config-loader.ts
├── types.ts ← ResolvedTargetBase, RawTargetConfig, CheckResult,
│ ExpectOperator, CheckFailure, StoredTarget 等公共类型
├── utils.ts ← parseSize, parseDuration
├── expect/ ← 断言基础设施(所有 checker 共享)
│ ├── types.ts ← ExpectResult 等共享类型
│ ├── operator.ts ← applyOperator, evaluateJsonPath, checkExpectValue
│ ├── duration.ts ← checkDuration
│ ├── failure.ts ← errorFailure, mismatchFailure, truncateActual
│ └── validate-operator.ts ← validateOperatorObject, isJsonValue
├── schema/ ← 配置 schema 体系
│ ├── builder.ts ← createProbeConfigSchema从 registry 动态构建)
│ ├── fragments.ts ← 共享 schema 片段
│ ├── validate.ts ← Ajv 校验入口
│ ├── issues.ts ← issue 类型和工具
│ ├── types.ts
│ └── export.ts
└── runner/
├── index.ts ← 显式注册列表
├── registry.ts ← CheckerRegistry
├── types.ts ← CheckerDefinition 接口(使用 base 类型)
├── http/
│ ├── index.ts ← re-export HttpChecker
│ ├── types.ts ← HttpTargetConfig, ResolvedHttpTarget, HttpExpectConfig 等
│ ├── schema.ts ← TypeBox schemas
│ ├── execute.ts ← class HttpChecker
│ ├── expect.ts ← checkStatus, checkHeaders
│ ├── body.ts ← checkBodyExpect从 shared 搬来)
│ └── validate.ts ← validateHttpConfig + validateBodyRules 等
├── command/
│ ├── index.ts ← re-export CommandChecker
│ ├── types.ts ← CommandTargetConfig, ResolvedCommandTarget 等
│ ├── schema.ts ← TypeBox schemas
│ ├── execute.ts ← class CommandChecker
│ ├── expect.ts ← checkExitCode
│ ├── text.ts ← checkTextRules从 shared 搬来)
│ └── validate.ts ← validateCommandConfig + validateTextRules
└── [future-checker]/ ← 新增 checker 模板
├── index.ts
├── types.ts
├── schema.ts
├── execute.ts
├── expect.ts
└── validate.ts
```
## 依赖方向约束
```
engine.ts / store.ts / config-loader.ts
▼ 依赖
runner/registry.ts + runner/types.ts + types.ts (base)
▼ 依赖
runner/http/ / runner/command/ / runner/[future]/
▼ 依赖
expect/ (断言基础设施) + schema/fragments.ts + utils.ts
```
禁止checker 之间横向依赖、expect/ 依赖 runner/、schema/ 依赖 runner/。
## Risks / Trade-offs
- **[编译期类型安全降低]** → 外部消费方engine、store不再能通过联合类型 narrow 到具体 checker 类型。缓解:这些消费方本来就不应该知道具体 checker 内部结构,这是设计意图而非缺陷。
- **[大量 import 路径变更]** → 所有测试文件和内部引用都需要更新。缓解:纯机械操作,可批量处理;项目未上线无兼容性负担。
- **[validate.ts 拆分复杂度]** → 原文件混合了通用和专属逻辑,拆分时需要仔细处理共享的辅助函数。缓解:`isPlainRecord` 等小工具可以在两处各自内联或放入 utils。

View File

@@ -1,36 +0,0 @@
## Why
当前 checker 的类型定义、校验逻辑、共享工具分散在多个层级目录中,新增一个 checker 需要修改顶层 `types.ts`(联合类型)、`runner/shared/`(如果有新的 expect 模式)、`config-contract/`(如果有新的 schema 片段)等多处文件。项目的核心就是 checker需要让每个 checker 的代码尽可能内聚——新增 checker 只需创建一个目录 + 在注册列表加一行,其他文件零修改。
## What Changes
-`ResolvedTarget``TargetConfig` 从硬编码联合类型改为 base interface各 checker 内部自行 narrow
- 将各 checker 专属类型(`HttpTargetConfig``ResolvedHttpTarget``CommandExpectConfig` 等)从顶层 `types.ts` 搬入各自 checker 目录的 `types.ts`
-`runner/shared/` 中仅单个 checker 使用的模块搬入对应 checker 目录(`body.ts``http/``text.ts``command/`
-`runner/shared/` 中真正跨 checker 共享的断言基础设施(`operator.ts``duration.ts``failure.ts`)提升为 `checker/expect/` 目录
-`shared/validate.ts` 拆分:通用 operator 校验 → `expect/validate-operator.ts`body 规则校验 → `http/validate.ts`text 规则校验 → `command/validate.ts`
-`config-contract/` 重命名为 `schema/`,内部 `schema.ts` 重命名为 `builder.ts`
-`size.ts``config-loader.ts` 中的 `parseDuration` 合并到 `utils.ts`
- 各 checker 的 `runner.ts` 重命名为 `execute.ts``contract.ts` 重命名为 `schema.ts`
- 各 checker 新增 `index.ts` 作为统一出口(仅 re-export
- `runner/index.ts` 改为显式列表注册模式
-`DefaultsConfig` 从硬编码联合(`command?: CommandDefaultsConfig; http?: HttpDefaultsConfig`)改为宽松 base 形式(`Record<string, unknown>` + 公共字段),各 checker validate 时自行 narrow
## Capabilities
### New Capabilities
- `checker-cohesion-structure`: 定义重构后 checker 目录的内聚结构规范,包括每个 checker 目录应包含的文件、职责划分、依赖方向约束,以及新增 checker 的最小改动清单
### Modified Capabilities
- `checker-runner-abstraction`: `CheckerDefinition` 接口的 `resolve`/`execute`/`serialize` 方法签名从具体联合类型改为 base interface共享 expect 断言函数的物理位置从 `runner/shared/` 变更为 `checker/expect/`(仅路径变化,行为不变)
## Impact
- 影响 `src/server/checker/` 目录下几乎所有文件的 import 路径
- `types.ts` 大幅瘦身,联合类型删除
- `runner/shared/` 目录删除,内容分散到 `expect/` 和各 checker 目录
- `config-contract/` 目录重命名为 `schema/`
- 所有现有测试的 import 路径需要同步更新
- 不影响外部 API、配置文件格式、运行时行为

View File

@@ -1,149 +0,0 @@
## ADDED Requirements
### Requirement: Checker 目录内聚结构
每个 checker SHALL 以独立目录形式存在于 `src/server/checker/runner/<type>/`,目录内 SHALL 包含该 checker 的全部类型定义、schema 声明、语义校验、执行逻辑和断言逻辑。
#### Scenario: HTTP checker 目录完整性
- **WHEN** 开发者查看 `src/server/checker/runner/http/` 目录
- **THEN** 该目录 SHALL 包含 `index.ts``types.ts``schema.ts``execute.ts``expect.ts``body.ts``validate.ts`
#### Scenario: Command checker 目录完整性
- **WHEN** 开发者查看 `src/server/checker/runner/command/` 目录
- **THEN** 该目录 SHALL 包含 `index.ts``types.ts``schema.ts``execute.ts``expect.ts``text.ts``validate.ts`
#### Scenario: 新增 checker 最小改动
- **WHEN** 开发者新增一个 checker 类型(如 dns
- **THEN** 开发者 SHALL 只需创建 `src/server/checker/runner/dns/` 目录及其内部文件,并在 `runner/index.ts` 注册列表中添加一行 import 和一行数组项
### Requirement: Checker 目录文件职责
每个 checker 目录内的文件 SHALL 遵循统一的职责划分。
#### Scenario: index.ts 仅做 re-export
- **WHEN** 开发者查看某 checker 的 `index.ts`
- **THEN** 该文件 SHALL 仅包含对 `execute.ts` 中 Checker 类的 re-export不包含任何逻辑
#### Scenario: types.ts 包含该 checker 全部专属类型
- **WHEN** 开发者需要该 checker 的配置类型、resolved 类型或 expect 类型
- **THEN** 这些类型 SHALL 全部定义在该 checker 目录的 `types.ts` 中,不在顶层 `types.ts`
#### Scenario: schema.ts 包含 TypeBox schema 定义
- **WHEN** 开发者需要该 checker 的 config/defaults/expect schema
- **THEN** 这些 schema SHALL 定义在该 checker 目录的 `schema.ts`
#### Scenario: execute.ts 包含 Checker 类实现
- **WHEN** 开发者需要查看该 checker 的执行逻辑
- **THEN** Checker 类(实现 CheckerDefinition 接口SHALL 定义在 `execute.ts`
#### Scenario: validate.ts 包含该 checker 全部语义校验
- **WHEN** 开发者需要查看该 checker 的配置校验逻辑
- **THEN** 该 checker 专属的语义校验函数 SHALL 全部定义在 `validate.ts`
#### Scenario: expect.ts 包含该 checker 专属断言
- **WHEN** 开发者需要查看该 checker 的断言逻辑
- **THEN** 该 checker 专属的断言函数 SHALL 定义在 `expect.ts`
### Requirement: 断言基础设施目录
系统 SHALL 在 `src/server/checker/expect/` 目录中提供所有 checker 共享的断言基础设施。
#### Scenario: expect 共享类型位置
- **WHEN** 任何 checker 需要使用断言相关的共享类型(如 `ExpectResult`
- **THEN** 这些类型 SHALL 从 `src/server/checker/expect/types.ts` 导入
#### Scenario: operator 断言引擎位置
- **WHEN** 任何 checker 需要使用 `applyOperator``evaluateJsonPath``checkExpectValue`
- **THEN** 这些函数 SHALL 从 `src/server/checker/expect/operator.ts` 导入
#### Scenario: duration 断言位置
- **WHEN** 任何 checker 需要使用 `checkDuration`
- **THEN** 该函数 SHALL 从 `src/server/checker/expect/duration.ts` 导入
#### Scenario: failure 构造器位置
- **WHEN** 任何 checker 需要使用 `errorFailure``mismatchFailure`
- **THEN** 这些函数 SHALL 从 `src/server/checker/expect/failure.ts` 导入
#### Scenario: operator 校验位置
- **WHEN** 任何 checker 的 validate 需要使用 `validateOperatorObject`
- **THEN** 该函数 SHALL 从 `src/server/checker/expect/validate-operator.ts` 导入
#### Scenario: ExpectResult 类型位置
- **WHEN** 任何 checker 需要使用 `ExpectResult` 类型
- **THEN** 该类型 SHALL 从 `src/server/checker/expect/types.ts` 导入
### Requirement: Schema 目录结构
系统 SHALL 在 `src/server/checker/schema/` 目录中组织配置 schema 体系,替代原 `config-contract/` 目录。
#### Scenario: schema 目录包含 builder
- **WHEN** 系统需要从 registry 动态构建整体配置 schema
- **THEN** 该逻辑 SHALL 位于 `src/server/checker/schema/builder.ts`
#### Scenario: schema 目录包含 fragments
- **WHEN** checker 的 schema.ts 需要引用共享 schema 片段(如 durationSchema、sizeSchema
- **THEN** 这些片段 SHALL 从 `src/server/checker/schema/fragments.ts` 导入
#### Scenario: schema 目录包含 Ajv 校验入口
- **WHEN** config-loader 需要执行契约校验
- **THEN** 校验入口 SHALL 位于 `src/server/checker/schema/validate.ts`
#### Scenario: schema 目录包含 issue 工具
- **WHEN** 任何校验逻辑需要构造 ConfigValidationIssue
- **THEN** issue 类型和工具函数 SHALL 从 `src/server/checker/schema/issues.ts` 导入
### Requirement: 工具函数归集
系统 SHALL 在 `src/server/checker/utils.ts` 中提供纯工具函数。
#### Scenario: parseSize 位置
- **WHEN** 任何模块需要解析 size 字符串(如 "100MB"
- **THEN** `parseSize` SHALL 从 `src/server/checker/utils.ts` 导入
#### Scenario: parseDuration 位置
- **WHEN** 任何模块需要解析 duration 字符串(如 "30s"
- **THEN** `parseDuration` SHALL 从 `src/server/checker/utils.ts` 导入
### Requirement: 依赖方向约束
checker 系统内的模块依赖 SHALL 遵循严格的分层方向。
#### Scenario: checker 之间无横向依赖
- **WHEN** 开发者查看任何 checker 目录的 import 语句
- **THEN** 该 checker SHALL NOT 导入其他 checker 目录的任何模块
#### Scenario: expect/ 不依赖 runner/
- **WHEN** 开发者查看 `expect/` 目录的 import 语句
- **THEN** `expect/` 中的文件 SHALL NOT 导入 `runner/` 目录的任何模块
#### Scenario: schema/ 不依赖 runner/ 的具体 checker
- **WHEN** 开发者查看 `schema/` 目录的 import 语句
- **THEN** `schema/` 中的文件 SHALL 仅通过 `CheckerDefinition` 接口与 checker 交互SHALL NOT 直接导入具体 checker 目录
### Requirement: 显式注册列表
系统 SHALL 在 `src/server/checker/runner/index.ts` 中使用显式 import 列表注册所有 checker。
#### Scenario: 注册入口结构
- **WHEN** 开发者查看 `runner/index.ts`
- **THEN** 该文件 SHALL 包含所有 checker 的静态 import 和一个 checker 实例数组,通过循环调用 `registry.register()` 完成注册
#### Scenario: 新增 checker 注册
- **WHEN** 开发者新增一个 checker
- **THEN** 开发者 SHALL 在 `runner/index.ts` 中添加一行 import 和一行数组项,无需修改其他文件
### Requirement: 公共类型文件瘦身
顶层 `src/server/checker/types.ts` SHALL 仅保留跨 checker 共享的 base 类型和存储相关类型。
#### Scenario: types.ts 不包含 checker 专属类型
- **WHEN** 开发者查看顶层 `types.ts`
- **THEN** 该文件 SHALL NOT 包含 `HttpTargetConfig``ResolvedHttpTarget``CommandExpectConfig``BodyRule``TextRule` 等 checker 专属类型
#### Scenario: types.ts 保留 base 类型
- **WHEN** 开发者查看顶层 `types.ts`
- **THEN** 该文件 SHALL 包含 `ResolvedTargetBase``RawTargetConfig``DefaultsConfig``CheckResult``ExpectOperator``CheckFailure``StoredTarget``StoredCheckResult``JsonValue` 等公共类型
#### Scenario: ResolvedTargetBase 替代联合类型
- **WHEN** engine、store、config-loader 需要引用 resolved target 类型
- **THEN** 这些模块 SHALL 使用 `ResolvedTargetBase` interface不再使用硬编码联合类型
#### Scenario: DefaultsConfig 为宽松 base 形式
- **WHEN** 开发者查看顶层 `types.ts` 中的 `DefaultsConfig`
- **THEN** 该 interface SHALL 仅包含公共字段(`interval?``timeout?`)和 index signature`[checkerKey: string]: unknown`SHALL NOT 包含 `command?``http?` 等 checker 专属字段
#### Scenario: 各 checker validate 自行 narrow defaults
- **WHEN** checker 的 `validate()` 方法需要访问自身的 defaults 配置
- **THEN** checker SHALL 从 `DefaultsConfig` 中通过 `defaults[configKey]` 获取并自行 narrow 为具体类型

View File

@@ -1,59 +0,0 @@
## MODIFIED Requirements
### Requirement: Checker 接口定义
系统 SHALL 在 `src/server/checker/runner/types.ts` 中定义面向扩展的 `CheckerDefinition`,包含 `type``configKey`、TypeBox 配置契约、启动期语义校验、`resolve``execute``serialize` 成员。`CheckerContext` SHALL 包含引擎注入的 `AbortSignal`。接口方法的参数和返回值 SHALL 使用 base interface 类型(`RawTargetConfig``ResolvedTargetBase`),各 checker 实现内部自行 narrow 到具体类型。
#### Scenario: Checker 接口包含必要方法
- **WHEN** 开发者实现一个新的 Checker
- **THEN** 该实现 MUST 提供 `type`(字符串标识)、`configKey`配置分组名、TypeBox 配置契约、启动期语义校验、`resolve(target, context)`(解析配置并填充默认值)、`execute(target, ctx)`(执行探测返回 CheckResult`serialize(target)`(返回 target 展示文本和 config JSON
#### Scenario: CheckerContext 注入 signal
- **WHEN** 引擎调用 `checker.execute(target, ctx)`
- **THEN** `ctx.signal` SHALL 是一个由引擎创建的 `AbortSignal`,在超时或引擎关闭时 abort
#### Scenario: resolve 不承担通用契约校验
- **WHEN** config-loader 调用 checker.resolve()
- **THEN** checker.resolve() SHALL 假定配置已经通过 TypeBox/Ajv 契约校验和启动期语义校验,只负责默认值填充、路径解析和领域配置转换
#### Scenario: type 与 configKey 默认一致
- **WHEN** checker 定义 `type: "tcp"`
- **THEN** checker 的 `configKey` SHALL 默认使用 `"tcp"`,对应 target 的 `tcp` 分组和 defaults.tcp 分组
#### Scenario: 接口方法使用 base 类型
- **WHEN** 开发者查看 `CheckerDefinition` 接口签名
- **THEN** `resolve` 的参数 SHALL 为 `RawTargetConfig`,返回值 SHALL 为 `ResolvedTargetBase``execute` 的参数 SHALL 为 `ResolvedTargetBase``serialize` 的参数 SHALL 为 `ResolvedTargetBase`
#### Scenario: checker 实现内部 narrow
- **WHEN** HttpChecker 的 execute 方法接收 `ResolvedTargetBase` 参数
- **THEN** 方法内部 SHALL 将参数 narrow 为 `ResolvedHttpTarget`(通过 type assertion然后使用具体类型的字段
### Requirement: 共享 expect 断言函数
系统 SHALL 在 `src/server/checker/expect/` 中提供可被多个 checker 复用的 expect 函数。checker 专用的 expect 函数 SHALL 保留在各自子包内。仅被单个 checker 使用的断言模块 SHALL 位于该 checker 目录内。
#### Scenario: 共享 duration 断言
- **WHEN** 任何 checker 需要校验执行耗时
- **THEN** SHALL 调用 `expect/duration.ts` 中的 `checkDuration(durationMs, maxDurationMs?)`,返回统一的 `ExpectResult`
#### Scenario: 共享 operator 断言
- **WHEN** 任何 checker 需要对值执行 operator 匹配
- **THEN** SHALL 调用 `expect/operator.ts` 中的 `applyOperator(actual, op)`
#### Scenario: 共享 failure 构造
- **WHEN** 任何 checker 需要构造 CheckFailure 对象
- **THEN** SHALL 调用 `expect/failure.ts` 中的 `errorFailure()``mismatchFailure()`
#### Scenario: HTTP body 断言位于 HTTP 目录
- **WHEN** HTTP checker 需要对响应体执行 contains/regex/json/css/xpath 规则校验
- **THEN** SHALL 调用 `runner/http/body.ts` 中的 `checkBodyExpect(body, rules)`
#### Scenario: Command text 断言位于 Command 目录
- **WHEN** Command checker 需要对 stdout/stderr 执行文本规则校验
- **THEN** SHALL 调用 `runner/command/text.ts` 中的 `checkTextRules(text, rules, phase)`
#### Scenario: HTTP 专用 expect
- **WHEN** HTTP checker 需要校验响应状态码和响应头
- **THEN** SHALL 调用 `runner/http/expect.ts` 中的 `checkStatus()``checkHeaders()`
#### Scenario: Command 专用 expect
- **WHEN** Command checker 需要校验退出码
- **THEN** SHALL 调用 `runner/command/expect.ts` 中的 `checkExitCode()`

View File

@@ -1,56 +0,0 @@
## 1. 基础设施搭建
- [x] 1.1 创建 `src/server/checker/utils.ts`,将 `size.ts``parseSize``config-loader.ts``parseDuration``DURATION_REGEX` 迁入
- [x] 1.2 创建 `src/server/checker/expect/` 目录,创建 `expect/types.ts` 放置 `ExpectResult` 等共享类型
- [x] 1.3 将 `runner/shared/operator.ts` 迁入为 `expect/operator.ts`
- [x] 1.4 将 `runner/shared/failure.ts` 迁入为 `expect/failure.ts`
- [x] 1.5 将 `runner/shared/duration.ts` 迁入为 `expect/duration.ts``ExpectResult` 类型提取到 `expect/types.ts`
- [x] 1.6 从 `runner/shared/validate.ts` 中提取 `validateOperatorObject``isJsonValue``validateOperatorValue``isPlainRecord``expect/validate-operator.ts`
## 2. Schema 目录重组
- [x] 2.1 将 `config-contract/` 目录重命名为 `schema/`
- [x] 2.2 将 `schema/schema.ts` 重命名为 `schema/builder.ts`
- [x] 2.3 更新 `schema/` 内部文件的相互引用路径
- [x] 2.4 更新外部对 `config-contract/` 的所有 import 路径config-loader.ts、runner/shared/validate.ts 等)
## 3. 类型系统重构
- [x] 3.1 在顶层 `types.ts` 中创建 `ResolvedTargetBase``RawTargetConfig` base interface
- [x] 3.2 将 HTTP 专属类型(`HttpTargetConfig``ResolvedHttpTarget``HttpExpectConfig``HttpDefaultsConfig``ResolvedHttpConfig``BodyRule``CssRule``JsonRule``XpathRule``HeaderExpect`)迁入 `runner/http/types.ts`
- [x] 3.3 将 Command 专属类型(`CommandTargetConfig``ResolvedCommandTarget``CommandExpectConfig``CommandDefaultsConfig``ResolvedCommandConfig`)迁入 `runner/command/types.ts`
- [x] 3.4 删除顶层 `types.ts` 中的 `ResolvedTarget` 联合类型和 `TargetConfig` 联合类型,将 `TextRule` 迁入 command/types.ts
- [x] 3.5 将 `DefaultsConfig` 改为宽松 base 形式(仅保留 `interval?``timeout?` + index signature`CommandDefaultsConfig` 迁入 command/types.ts`HttpDefaultsConfig` 迁入 http/types.ts
- [x] 3.6 更新 `runner/types.ts``CheckerDefinition` 接口签名,使用 `RawTargetConfig``ResolvedTargetBase`
- [x] 3.7 更新 `engine.ts``store.ts``config-loader.ts` 的类型引用为 `ResolvedTargetBase``RawTargetConfig`
## 4. HTTP Checker 内聚化
- [x] 4.1 将 `runner/http/runner.ts` 重命名为 `runner/http/execute.ts`
- [x] 4.2 将 `runner/http/contract.ts` 重命名为 `runner/http/schema.ts`
- [x] 4.3 将 `runner/shared/body.ts` 迁入 `runner/http/body.ts`
- [x] 4.4 将 `runner/shared/validate.ts` 中的 `validateBodyRules``validateCssRule``validateJsonRule``validateXpathRule``validateRegexRule``validateSingleBodyRule``validateJsonPath` 合并到 `runner/http/validate.ts`
- [x] 4.5 创建 `runner/http/index.ts`re-export `HttpChecker`
- [x] 4.6 更新 `runner/http/` 内所有文件的 import 路径
## 5. Command Checker 内聚化
- [x] 5.1 将 `runner/command/runner.ts` 重命名为 `runner/command/execute.ts`
- [x] 5.2 将 `runner/command/contract.ts` 重命名为 `runner/command/schema.ts`
- [x] 5.3 将 `runner/shared/text.ts` 迁入 `runner/command/text.ts`
- [x] 5.4 将 `runner/shared/validate.ts` 中的 `validateTextRules` 合并到 `runner/command/validate.ts`
- [x] 5.5 创建 `runner/command/index.ts`re-export `CommandChecker`
- [x] 5.6 更新 `runner/command/` 内所有文件的 import 路径
## 6. 注册入口改造
- [x] 6.1 重写 `runner/index.ts` 为显式列表注册模式import 列表 + checker 数组 + 循环注册)
- [x] 6.2 删除 `runner/shared/` 目录(确认所有内容已迁移完毕)
- [x] 6.3 删除 `src/server/checker/size.ts`(已迁入 utils.ts
## 7. 测试与质量保障
- [x] 7.1 更新所有测试文件的 import 路径
- [x] 7.2 执行完整测试套件,确保所有测试通过
- [x] 7.3 执行 lint 和格式检查,确保代码质量
- [x] 7.4 确认新增 checker 只需一个目录 + 一行注册