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

11 KiB
Raw Blame History

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-unresolvedimport/no-deprecated 错误

Scenario: 排除第三方模板目录

  • WHEN ESLint 运行检查
  • THEN 系统 MUST 排除 .agents/ 等第三方模板目录,不检查其中的代码

Scenario: 排除生成产物和锁文件

  • WHEN ESLint 运行检查
  • THEN 系统 MUST 排除 dist/.build/node_modules/openspec/.opencode/.claude/.codex/*.bun-buildbun.lockdata/ 等非源码目录

Requirement: Prettier 代码格式门禁

项目 SHALL 通过 eslint-plugin-prettier 将 Prettier 格式检查集成为 ESLint 规则,使 lint 命令同时覆盖代码质量和格式检查(原独立的 format:check 命令不再存在,格式检查统一通过 lint 完成)。项目仍保留独立的 format 命令(prettier --write用于快速格式化。Prettier 配置 SHALL 显式声明 printWidthsemisingleQuotetrailingCommabracketSpacingarrowParensendOfLinetabWidthuseTabs 全部格式化参数。

Scenario: 检查代码格式

  • WHEN 开发者运行 bun run lint
  • THEN ESLint SHALL 通过 eslint-plugin-prettier 检查受管理文件格式,并在发现未格式化文件时以非零状态退出

Scenario: 自动格式化代码

  • WHEN 开发者运行 bun run formateslint --fix
  • THEN 系统 SHALL 使用 Prettier 重写受管理文件的格式

Scenario: 排除 OpenSpec 文档和生成产物

  • WHEN Prettier 格式化或格式检查运行(通过 ESLint 或独立 Prettier 命令)
  • THEN 系统 MUST 排除 openspec/dist/.build/node_modules/bun.lockskills-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 typeimport 语句
  • 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 指令的情况下通过