## MODIFIED Requirements ### Requirement: Checker 接口定义 系统 SHALL 在 `src/server/checker/runner/types.ts` 中定义面向扩展的泛型 `CheckerDefinition`,包含 `type`、`configKey`、TypeBox 配置契约、启动期语义校验、`resolve`、`execute`、`serialize` 成员。泛型参数 SHALL 约束 `execute` 和 `serialize` 方法的 target 参数类型,使 checker 实现内部获得编译期类型安全。默认泛型参数 `= ResolvedTargetBase` 保证中间层(registry、engine、config-loader)无需指定泛型。 #### Scenario: Checker 接口包含必要方法 - **WHEN** 开发者实现一个新的 Checker - **THEN** 该实现 MUST 提供 `type`(字符串标识)、`configKey`(配置分组名)、TypeBox 配置契约、启动期语义校验、`resolve(target, context): TResolved`(解析配置并填充默认值)、`execute(target: TResolved, ctx)`(执行探测返回 CheckResult)和 `serialize(target: TResolved)`(返回 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: 接口方法使用泛型约束 - **WHEN** 开发者查看 `CheckerDefinition` 接口签名 - **THEN** `resolve` 的返回值 SHALL 为 `TResolved`;`execute` 的参数 SHALL 为 `TResolved`;`serialize` 的参数 SHALL 为 `TResolved` #### Scenario: checker 实现无需手动断言 - **WHEN** HttpChecker 实现 `CheckerDefinition` - **THEN** `execute` 方法的 target 参数类型 SHALL 直接为 `ResolvedHttpTarget`,无需在方法内部使用 `as` 类型断言 #### Scenario: registry 使用默认泛型参数 - **WHEN** CheckerRegistry 存储和返回 checker 实例 - **THEN** registry 内部 SHALL 使用 `CheckerDefinition`(等价于 `CheckerDefinition`),实现类型擦除 ### Requirement: CheckerRegistry 注册中心 系统 SHALL 在 `src/server/checker/runner/registry.ts` 中提供 `CheckerRegistry` 类,支持 `register(checker)`、`get(type)` 和 `supportedTypes`。重复注册同一 type SHALL 抛出错误。registry 内部 SHALL 存储 `CheckerDefinition`(使用默认泛型参数),对外提供类型擦除后的接口。 #### Scenario: 注册并获取 Checker - **WHEN** 调用 `registry.register(new HttpChecker())` 后再调用 `registry.get("http")` - **THEN** 返回的 SHALL 是之前注册的 HttpChecker 实例(类型为 `CheckerDefinition`) #### Scenario: 获取未注册的 type - **WHEN** 调用 `registry.get("unknown")` 且未注册对应 type 的 checker - **THEN** 系统 SHALL 抛出错误,提示不支持的 probe type #### Scenario: 重复注册 - **WHEN** 同一 type 值被重复 `register()` - **THEN** 系统 SHALL 抛出错误,提示该 type 已注册 #### Scenario: 查询支持的 type 列表 - **WHEN** 注册了 "http" 和 "command" 两个 checker 后查询 `registry.supportedTypes` - **THEN** 返回的数组 SHALL 包含 `["http", "command"]`(按注册顺序)