质量门控

wescode 的质量门控(QualityGate)是一套多层次的自动化验证机制,确保 AI 生成的代码符合项目标准。从基础语法检查到行为基线对比,渐进式地保障代码质量。


核心理念

问题背景

AI 编程助手面临一个核心挑战:局部正确 ≠ 全局正确。

AI 可能生成一段语法正确、逻辑合理的代码,但它可能:

QualityGate 的定位

QualityGate 是 wescode 五层能力栈中 L4(验证层)的核心组件。它在 AI 编辑代码后自动执行验证,在问题到达用户之前拦截。


渐进验证层次

QualityGate 采用 L0 → L2.5 的渐进验证架构:

L0 — 语法验证

目标:确保代码能通过编译/解析。

语言L0 验证命令
Gogo build ./...
TypeScripttsc --noEmit
Pythonpython -m py_compile
Rustcargo check

触发时机:每次 AI 编辑文件后自动执行。

速度:通常 1-5 秒。

L1 — Lint 验证

目标:确保代码符合项目的静态分析规则。

工具检查内容
go vetGo 静态分析
ESLintJavaScript/TypeScript 规范
golangci-lintGo 综合 lint
pylint / ruffPython lint
clippyRust lint

触发时机:L0 通过后自动执行。

速度:通常 2-10 秒。

L2 — 测试验证

目标:确保相关测试仍然通过。

AI 不会运行全部测试,而是智能选择与本次修改相关的测试:

  1. 直接相关测试:修改了 user.go,运行 user_test.go
  2. 间接相关测试:通过 CKG 调用图找到依赖变更函数的测试
  3. 范围限制:最多运行受影响包内的测试,不跑全量
# 示例:AI 修改了 internal/service/user.go
# L2 自动运行:
go test ./internal/service/ -run TestUser -v

触发时机:L1 通过后自动执行。

速度:通常 5-30 秒。

L2.5 — 行为基线验证

目标:检测隐式的行为变化。

L2.5 是 wescode 独有的验证层次,它超越了"测试通过"的维度,检查代码的行为是否发生了非预期的改变。

L2.5 的检测包括:

注意: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 配置:

禁用验证

在某些场景下可能需要临时禁用验证:


验证结果处理

通过

所有验证层通过后,AI 的修改被确认为有效。状态栏显示绿色勾号。

失败

验证失败时,AI 会收到详细的错误信息:

QualityGate L0 失败:
  internal/service/user.go:45:12: undefined: UserRepo

AI 分析后自动修复:
  → 添加缺失的导入
  → 重新运行 L0
  → 通过

自动修复

AI 在收到验证失败的反馈后,会尝试自动修复:

  1. 编译错误:根据错误信息自动修复(缺失导入、类型不匹配等)
  2. Lint 警告:根据规则自动调整代码风格
  3. 测试失败:分析失败原因,调整实现或更新测试

修复循环

QualityGate 的修复循环有上限保护:

编辑 → L0 失败 → 修复 → L0 通过 → L1 失败 → 修复 → L1 通过 → L2 通过 ✅
                                                                    
编辑 → L0 失败 → 修复 → L0 失败 → 修复 → L0 失败 → 放弃,报告错误 ❌

最多重试 3 次。超过后报告错误让用户介入。


与 CSE 的协作

约束满足引擎

CSE(Constraint Satisfaction Engine)与 QualityGate 协同工作:

CSE 提供的约束

CSE 有 13 个 Checker,覆盖不同维度的约束检查:

约束类别示例
导入约束不引入禁止的依赖
命名约束遵循项目命名规范
结构约束不破坏现有接口
安全约束不引入已知的安全模式

使用示例

示例 1:编译错误自动修复

帮我在 UserService 中添加一个批量删除方法

AI 编写代码后,QualityGate 检测到编译错误(缺少 context 包导入),自动修复并重新验证。整个过程对用户透明。

示例 2:测试失败反馈

请修改 calculateTotal 函数,使其支持折扣

AI 修改后 L2 测试失败。AI 分析失败的测试用例,发现需要更新测试的期望值,自动更新测试并重新验证通过。

示例 3:Lint 修复

帮我重构这段代码

AI 重构后 golangci-lint 报告了风格问题。AI 根据 lint 规则自动调整代码格式并通过验证。


注意事项

  1. 验证耗时:L2 测试验证可能需要较长时间,AI 会在验证期间继续工作
  2. 首次验证:首次运行可能需要下载依赖、编译缓存,后续会快很多
  3. 网络依赖:部分验证可能需要网络访问(下载依赖),离线时可能失败
  4. 误报处理:如果 QualityGate 误报(如 flaky 测试),可以告诉 AI 跳过
  5. CycleDetector:验证循环受 CycleDetector 保护,不会无限重试

最佳实践

  1. 保持测试通过:QualityGate 的有效性依赖于项目测试的健康度
  2. 配置 lint 规则:确保项目有清晰的 lint 配置,帮助 AI 写出符合规范的代码
  3. 利用 CI 配置:如果项目有 CI,QualityGate 会参考 CI 配置来选择验证命令
  4. 信任但验证:即使 QualityGate 通过,重要修改仍建议人工复审