质量门控
wescode 的质量门控(QualityGate)是一套多层次的自动化验证机制,确保 AI 生成的代码符合项目标准。从基础语法检查到行为基线对比,渐进式地保障代码质量。
核心理念
问题背景
AI 编程助手面临一个核心挑战:局部正确 ≠ 全局正确。
AI 可能生成一段语法正确、逻辑合理的代码,但它可能:
- 破坏了现有测试
- 不符合项目的编码规范
- 引入了隐式的行为变化
- 违反了项目的约束和惯例
QualityGate 的定位
QualityGate 是 wescode 五层能力栈中 L4(验证层)的核心组件。它在 AI 编辑代码后自动执行验证,在问题到达用户之前拦截。
渐进验证层次
QualityGate 采用 L0 → L2.5 的渐进验证架构:
L0 — 语法验证
目标:确保代码能通过编译/解析。
| 语言 | L0 验证命令 |
|---|---|
| Go | go build ./... |
| TypeScript | tsc --noEmit |
| Python | python -m py_compile |
| Rust | cargo check |
触发时机:每次 AI 编辑文件后自动执行。
速度:通常 1-5 秒。
L1 — Lint 验证
目标:确保代码符合项目的静态分析规则。
| 工具 | 检查内容 |
|---|---|
go vet | Go 静态分析 |
| ESLint | JavaScript/TypeScript 规范 |
| golangci-lint | Go 综合 lint |
| pylint / ruff | Python lint |
| clippy | Rust lint |
触发时机:L0 通过后自动执行。
速度:通常 2-10 秒。
L2 — 测试验证
目标:确保相关测试仍然通过。
AI 不会运行全部测试,而是智能选择与本次修改相关的测试:
- 直接相关测试:修改了
user.go,运行user_test.go - 间接相关测试:通过 CKG 调用图找到依赖变更函数的测试
- 范围限制:最多运行受影响包内的测试,不跑全量
# 示例:AI 修改了 internal/service/user.go
# L2 自动运行:
go test ./internal/service/ -run TestUser -v
触发时机:L1 通过后自动执行。
速度:通常 5-30 秒。
L2.5 — 行为基线验证
目标:检测隐式的行为变化。
L2.5 是 wescode 独有的验证层次,它超越了"测试通过"的维度,检查代码的行为是否发生了非预期的改变。
L2.5 的检测包括:
- API 契约变化:函数签名、返回类型的变化
- 错误处理变化:新增或移除了错误路径
- 副作用变化:数据库写入、文件操作、网络请求的变化
- 性能特征变化:算法复杂度的变化
注意:L2.5 目前处于实验阶段,需要项目配置基线数据才能生效。
EditPatrol 编辑巡检
什么是 EditPatrol?
EditPatrol 是 QualityGate 的实时监控组件。它在 AI 编辑代码的过程中持续检查,而不是等编辑完成后才验证。
工作机制
AI 写入文件
↓
EditPatrol 拦截
↓
├── 语法快速检查(<100ms)
├── 导入检查(是否引入了未声明的依赖)
├── 路径检查(是否写入了禁止区域)
└── 风格检查(是否违反项目约定)
↓
通过 → AI 继续
拒绝 → 提示 AI 修正
检查项
| 检查 | 说明 | 速度 |
|---|---|---|
| 语法完整性 | 确保写入的代码语法完整 | <50ms |
| 导入合法性 | 检查导入的包是否存在 | <100ms |
| 路径边界 | 确保不写入受保护的路径 | <10ms |
| 编码规范 | 缩进、命名等基础检查 | <50ms |
与 QualityGate 的关系
EditPatrol 是实时的轻量检查,QualityGate 是事后的深度验证:
编辑过程 ──── EditPatrol(实时拦截明显错误)
↓
编辑完成 ──── QualityGate L0(编译)
↓
──── QualityGate L1(lint)
↓
──── QualityGate L2(测试)
配置
验证命令配置
可以为项目自定义验证命令:
# .wescode/quality-gate.yaml(规划中)
l0:
command: "go build ./..."
timeout: 30s
l1:
command: "golangci-lint run ./..."
timeout: 60s
l2:
command: "go test ./... -short"
timeout: 120s
# 只运行相关测试
scope: "affected"
当前配置方式
当前版本中,QualityGate 的验证命令通过 CellSpec 的 hook 配置:
- QualityGate hook:在 CellSpec 中声明验证逻辑
- HostEnvironment:感知项目的构建工具和测试框架
- 自动推断:根据 WsIntel 的项目类型检测结果自动选择验证命令
禁用验证
在某些场景下可能需要临时禁用验证:
- Bench 模式:
wescode bench自动禁用 QualityGate L2(评测有自己的验证机制) - 快速迭代:在探索阶段可以临时跳过验证
验证结果处理
通过
所有验证层通过后,AI 的修改被确认为有效。状态栏显示绿色勾号。
失败
验证失败时,AI 会收到详细的错误信息:
QualityGate L0 失败:
internal/service/user.go:45:12: undefined: UserRepo
AI 分析后自动修复:
→ 添加缺失的导入
→ 重新运行 L0
→ 通过
自动修复
AI 在收到验证失败的反馈后,会尝试自动修复:
- 编译错误:根据错误信息自动修复(缺失导入、类型不匹配等)
- Lint 警告:根据规则自动调整代码风格
- 测试失败:分析失败原因,调整实现或更新测试
修复循环
QualityGate 的修复循环有上限保护:
编辑 → L0 失败 → 修复 → L0 通过 → L1 失败 → 修复 → L1 通过 → L2 通过 ✅
编辑 → L0 失败 → 修复 → L0 失败 → 修复 → L0 失败 → 放弃,报告错误 ❌
最多重试 3 次。超过后报告错误让用户介入。
与 CSE 的协作
约束满足引擎
CSE(Constraint Satisfaction Engine)与 QualityGate 协同工作:
- CSE 预防:在 AI 生成代码之前施加约束,减少错误产生
- QualityGate 验证:在代码生成之后验证是否符合约束
CSE 提供的约束
CSE 有 13 个 Checker,覆盖不同维度的约束检查:
| 约束类别 | 示例 |
|---|---|
| 导入约束 | 不引入禁止的依赖 |
| 命名约束 | 遵循项目命名规范 |
| 结构约束 | 不破坏现有接口 |
| 安全约束 | 不引入已知的安全模式 |
使用示例
示例 1:编译错误自动修复
帮我在 UserService 中添加一个批量删除方法
AI 编写代码后,QualityGate 检测到编译错误(缺少 context 包导入),自动修复并重新验证。整个过程对用户透明。
示例 2:测试失败反馈
请修改 calculateTotal 函数,使其支持折扣
AI 修改后 L2 测试失败。AI 分析失败的测试用例,发现需要更新测试的期望值,自动更新测试并重新验证通过。
示例 3:Lint 修复
帮我重构这段代码
AI 重构后 golangci-lint 报告了风格问题。AI 根据 lint 规则自动调整代码格式并通过验证。
注意事项
- 验证耗时:L2 测试验证可能需要较长时间,AI 会在验证期间继续工作
- 首次验证:首次运行可能需要下载依赖、编译缓存,后续会快很多
- 网络依赖:部分验证可能需要网络访问(下载依赖),离线时可能失败
- 误报处理:如果 QualityGate 误报(如 flaky 测试),可以告诉 AI 跳过
- CycleDetector:验证循环受 CycleDetector 保护,不会无限重试
最佳实践
- 保持测试通过:QualityGate 的有效性依赖于项目测试的健康度
- 配置 lint 规则:确保项目有清晰的 lint 配置,帮助 AI 写出符合规范的代码
- 利用 CI 配置:如果项目有 CI,QualityGate 会参考 CI 配置来选择验证命令
- 信任但验证:即使 QualityGate 通过,重要修改仍建议人工复审