1
0
Files
DiAL/openspec/specs/code-quality-gates/spec.md
lanyuanxiaoyao cfca03b4d6 refactor: 规范审查与重组,合并细粒度规范,清理过时内容
- 合并 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 审查提示文档
2026-05-22 18:55:18 +08:00

196 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Purpose
定义项目代码质量门禁、格式化检查、Git hooks 自动化质量门禁、提交信息格式校验、快速检查和完整验证命令的行为要求,确保开发者可以通过文档化命令稳定验证源码质量、基础测试和生产构建。
## Requirements
### Requirement: ESLint 代码质量门禁
项目 SHALL 提供 ESLint 代码质量门禁,用于审查 TypeScript、React 前端、脚本和测试代码中的质量问题。ESLint 配置 SHALL 包括 `@eslint/js` recommended 规则、`typescript-eslint` recommended-type-checked 和 stylistic-type-checked 规则、`eslint-plugin-perfectionist` 导入排序规则、`eslint-plugin-import` 导入验证规则,以及精选的单项类型安全和风格规则。
#### Scenario: 运行 lint 检查
- **WHEN** 开发者运行文档化的 lint 命令
- **THEN** 系统 SHALL 使用 ESLint 检查项目源码、脚本和测试代码,并在发现违规时以非零状态退出
#### Scenario: 检查 React Hooks 规则
- **WHEN** 前端 React 代码违反 Hooks 调用规则
- **THEN** lint 命令 MUST 失败并报告对应违规
#### Scenario: 保护前后端边界
- **WHEN** `src/web` 前端代码导入 `src/server` 后端运行时实现
- **THEN** lint 命令 MUST 失败并报告前后端边界违规
#### Scenario: 检测类型安全违规
- **WHEN** 代码中存在浮动的 Promise 未 await、any 类型泄漏到明确类型位置、模板字符串中包含非字符串化对象等类型安全隐患
- **THEN** lint 命令 MUST 失败并报告对应 `@typescript-eslint` 规则违规
#### Scenario: 检测导入路径错误
- **WHEN** 代码中导入路径指向不存在的文件或已废弃的路径
- **THEN** lint 命令 MUST 失败并报告 `import/no-unresolved``import/no-deprecated` 错误
#### Scenario: 排除第三方模板目录
- **WHEN** ESLint 运行检查
- **THEN** 系统 MUST 排除 `.agents/` 等第三方模板目录,不检查其中的代码
#### Scenario: 排除生成产物和锁文件
- **WHEN** ESLint 运行检查
- **THEN** 系统 MUST 排除 `dist/``.build/``node_modules/``openspec/``.opencode/``.claude/``.codex/``*.bun-build``bun.lock``data/` 等非源码目录
### Requirement: Prettier 代码格式门禁
项目 SHALL 通过 `eslint-plugin-prettier` 将 Prettier 格式检查集成为 ESLint 规则,使 `lint` 命令同时覆盖代码质量和格式检查(原独立的 `format:check` 命令不再存在,格式检查统一通过 `lint` 完成)。项目仍保留独立的 `format` 命令(`prettier --write`用于快速格式化。Prettier 配置 SHALL 显式声明 `printWidth``semi``singleQuote``trailingComma``bracketSpacing``arrowParens``endOfLine``tabWidth``useTabs` 全部格式化参数。
#### Scenario: 检查代码格式
- **WHEN** 开发者运行 `bun run lint`
- **THEN** ESLint SHALL 通过 eslint-plugin-prettier 检查受管理文件格式,并在发现未格式化文件时以非零状态退出
#### Scenario: 自动格式化代码
- **WHEN** 开发者运行 `bun run format``eslint --fix`
- **THEN** 系统 SHALL 使用 Prettier 重写受管理文件的格式
#### Scenario: 排除 OpenSpec 文档和生成产物
- **WHEN** Prettier 格式化或格式检查运行(通过 ESLint 或独立 Prettier 命令)
- **THEN** 系统 MUST 排除 `openspec/``dist/``.build/``node_modules/``bun.lock``skills-lock.json``.agents/``data/``*.bun-build``.opencode/``.claude/``.codex/` 和临时构建产物
#### Scenario: 格式化配置一致性
- **WHEN** 不同开发者在不同操作系统上运行格式化(通过 ESLint 或独立 Prettier
- **THEN** 由于所有格式化参数均显式定义,产物 SHALL 完全一致
### Requirement: pre-commit 自动质量检查
项目 SHALL 通过 husky 和 lint-staged 在 git commit 前自动对变更文件运行 ESLint含 Prettier 格式)检查。由于 eslint-plugin-prettier 已集成格式检查lint-staged SHALL 仅运行 `eslint --fix` 即可同时修复代码质量和格式问题。
#### Scenario: 变更 TypeScript 文件后提交
- **WHEN** 开发者 stage 了 `.ts``.tsx` 文件并执行 `git commit`
- **THEN** lint-staged SHALL 自动对变更文件运行 `eslint --fix`(含格式修复),修复后继续提交
#### Scenario: 变更 Markdown 或 JSON 文件后提交
- **WHEN** 开发者 stage 了 `.md``.json``.yaml``.yml` 文件并执行 `git commit`
- **THEN** lint-staged SHALL 自动对变更文件运行 `prettier --write`
#### Scenario: lint 检查失败阻止提交
- **WHEN** 变更文件存在无法自动修复的 ESLint 错误(含格式错误)
- **THEN** pre-commit hook MUST 以非零状态退出,阻止提交
#### Scenario: 无变更文件提交
- **WHEN** 开发者执行 `git commit` 但无 stage 文件
- **THEN** lint-staged SHALL 正常通过,不阻止提交
### Requirement: 提交信息格式校验
项目 SHALL 通过 commitlint 在 git commit 时校验提交信息必须符合 "类型: 简短描述" 格式,类型限定为 feat/fix/refactor/docs/style/test/chore。
#### Scenario: 有效的中文提交信息
- **WHEN** 开发者提交信息为 "feat: 新增导入排序功能"
- **THEN** commit-msg hook SHALL 通过校验
#### Scenario: 缺少类型前缀的提交信息
- **WHEN** 开发者提交信息为 "新增导入排序功能"(无 "feat:" 前缀)
- **THEN** commit-msg hook MUST 以非零状态退出,提示正确格式
#### Scenario: 无效的提交类型
- **WHEN** 开发者提交信息使用不在允许列表中的类型(如 "update: 修改配置"
- **THEN** commit-msg hook MUST 以非零状态退出,提示可用类型
### Requirement: husky 初始化自动化
项目 SHALL 通过 `prepare` 生命周期脚本在 `bun install` 时自动初始化 husky。
#### Scenario: 首次安装依赖
- **WHEN** 开发者运行 `bun install`
- **THEN** husky SHALL 自动初始化,安装 pre-commit 和 commit-msg hooks
#### Scenario: 已有 husky 配置时安装
- **WHEN** 开发者运行 `bun install` 且 husky 已初始化
- **THEN** husky 初始化 SHALL 跳过,不覆盖已有配置
### Requirement: TypeScript 未使用变量检测
项目 SHALL 启用 TypeScript `noUnusedLocals` 编译选项,将未使用的局部变量检测为编译错误。
#### Scenario: 存在未使用的局部变量
- **WHEN** TypeScript 代码中存在声明但未被引用的局部变量
- **THEN** `tsc --noEmit` MUST 以非零状态退出并报告未使用变量
### Requirement: TypeScript 索引签名属性访问检测
项目 SHALL 启用 TypeScript `noPropertyAccessFromIndexSignature` 编译选项,禁止通过点号访问未显式声明的属性。
#### Scenario: 通过点号访问 Record 动态属性
- **WHEN** 代码通过 `.property` 点号语法访问 `Record<string, T>` 类型或索引签名类型的属性
- **THEN** `tsc --noEmit` MUST 以非零状态退出,强制使用 `["property"]` 括号语法显式访问
### Requirement: ESLint 导入自动排序
项目 SHALL 通过 `eslint-plugin-perfectionist` 对导入语句进行自动排序,确保导入顺序一致性。
#### Scenario: 导入语句无序排列
- **WHEN** 文件中导入语句未按要求排序
- **THEN** `eslint --fix` SHALL 自动重排 import 声明和 named imports 内部顺序
#### Scenario: type import 与 value import 混合
- **WHEN** 文件中同时存在 `import type``import` 语句
- **THEN** perfectionist SHALL 正确识别并分别排序,不将 type 和 value 导入混淆
### Requirement: ESLint 导入路径验证
项目 SHALL 通过 `eslint-plugin-import` 验证导入路径的有效性和一致性。
#### Scenario: 导入不存在的模块路径
- **WHEN** 代码中导入了不存在或路径错误的模块
- **THEN** lint 命令 MUST 失败并报告 `import/no-unresolved` 错误
#### Scenario: 存在重复导入
- **WHEN** 同一个模块在同一文件中被多次导入
- **THEN** `eslint --fix` SHALL 自动合并重复导入为目标模块的单条导入
#### Scenario: 存在循环依赖
- **WHEN** 模块 A 导入模块 B同时模块 B 导入模块 A
- **THEN** lint 命令 MUST 报告 `import/no-cycle` 警告
### Requirement: 快速检查命令
项目 SHALL 提供快速 `check` 命令,用于日常开发期间验证代码质量和基础行为。
#### Scenario: 运行快速检查
- **WHEN** 开发者运行 `bun run check`
- **THEN** 系统 SHALL 依次执行 schema 检查、类型检查、lint含格式和单元/组件测试(`bun test`
#### Scenario: 快速检查失败
- **WHEN** `check` 中任一子检查失败
- **THEN** `check` MUST 以非零状态退出且不静默忽略失败
### Requirement: 分层测试运行命令
项目 SHALL 提供分层的测试运行命令,支持按需执行不同层级的测试。
#### Scenario: 运行全部单元和组件测试
- **WHEN** 开发者运行 `bun test`
- **THEN** 系统 SHALL 执行 `tests/` 目录下所有 `*.test.ts``*.test.tsx` 文件
### Requirement: 完整验证命令
项目 SHALL 提供完整 `verify` 命令,用于提交前或发布前验证当前源码、测试和生产构建。
#### Scenario: 运行完整验证
- **WHEN** 开发者运行 `bun run verify`
- **THEN** 系统 SHALL 先运行 `check`,再运行生产构建
#### Scenario: 完整验证失败
- **WHEN** `verify` 中任一阶段失败
- **THEN** `verify` MUST 以非零状态退出且不能继续声明验证成功
### Requirement: 测试代码 ESLint 禁用最小化
项目测试代码 SHALL 优先通过类型化 helper、类型化 mock、显式 no-op 和受控断言模式满足已启用的 ESLint 类型感知规则。受本变更审计的项目自有测试文件 MUST NOT 保留用于压制可通过代码结构解决的 `eslint-disable` 指令。
#### Scenario: 消除组件测试文件级禁用
- **WHEN** ESLint 检查 `tests/web/components/App.test.tsx`
- **THEN** 该文件 MUST 不使用文件级 `eslint-disable` 关闭 `@typescript-eslint/no-require-imports``@typescript-eslint/no-unsafe-*` 规则,并且测试中的 hook mock SHALL 使用类型化引用或等价方式访问 mock API
#### Scenario: 消除配置加载测试重复 await 禁用
- **WHEN** `tests/server/checker/config-loader.test.ts` 断言 `loadConfig()` 异步失败
- **THEN** 测试 SHALL 使用 helper 或显式 try/catch 断言错误实例与消息MUST 不通过逐行 `eslint-disable-next-line @typescript-eslint/await-thenable` 压制 Bun `expect(...).rejects` 类型不匹配
#### Scenario: 测试环境 no-op polyfill 保持可解释
- **WHEN** `tests/setup.ts` 为 jsdom 测试环境定义浏览器 API polyfill
- **THEN** intentional no-op SHALL 使用显式可解释写法表达MUST 不通过文件级 `eslint-disable @typescript-eslint/no-empty-function` 关闭空函数检查
#### Scenario: release 测试拦截 process.exit 保持窄作用域
- **WHEN** `tests/scripts/release.test.ts` 验证无效 release target 会触发 `process.exit(1)`
- **THEN** 测试 SHALL 使用受控 mock 或等价窄作用域替换并在断言后恢复MUST 不通过 `eslint-disable-next-line @typescript-eslint/unbound-method` 保存未绑定方法
#### Scenario: 质量门禁验证禁用清理
- **WHEN** 开发者运行 `bun run lint`
- **THEN** ESLint MUST 检查项目自有测试代码并在无上述 `eslint-disable` 指令的情况下通过