Harness Engineering 搭建指南(二):Rules 层 — 硬性约束体系

概述

系列定位:在项目中要搭建出完整的Harness Engineering四层文档体系,基本分为6步,接下来我会通过本系列共 6 篇文章,指导从零搭建 Harness Engineering 四层文档体系,最终实现从 BRD/PRD 到代码交付的一站式 AI 开发与自检闭环。

本篇定位:第 2 步------将 Step 1 定义的架构基线转化为 AI Agent 必须遵守的硬性规则,确保 AI 生成的代码符合项目技术栈和架构规范。


1. 什么是 Rules 层

1.1 定位

Rules 层是 Harness Engineering 四层体系中的约束层核心 ,位于 .qoder/rules/ 目录下。这些文件由 IDE 自动注入 AI Agent 的上下文,在所有任务中始终生效,无需手动加载。

1.2 与其他层的关系

复制代码
Rules 层(本步)          ← 硬性约束,始终生效,不可违反
Skills 层(Step 4)       ← 操作手册,按需触发,教 AI "怎么干"
Wiki 层(Step 3)         ← 知识库,按需加载,提供上下文
Changes 层(Step 5)       ← 变更管理,保障交付质量

关键区别 :Rules 层是"不可逾越的红线 ",Skills 层是"推荐的操作步骤"。Rules 违反时 AI 必须修正,Skills 建议不采纳时 AI 可以调整。

1.3 为什么必须先建 Rules 层

场景 没有 Rules 层 有 Rules 层
JSON 库选择 AI 可能用 Jackson AI 必须用 FastJSON
数据库访问 AI 可能直接注入 Mapper AI 必须用 DalManager.of()
事务管理 AI 可能用 @Transactional AI 必须用 TransactionTemplate
日志方式 AI 可能用 LoggerFactory AI 必须用 @Slf4j
模块依赖 AI 可能产生反向依赖 AI 必须遵守依赖方向

没有 Rules 层,AI 生成的代码会"看起来对"但不符合项目规范。


2. 需要创建的文件清单

复制代码
.qoder/
└── rules/
    ├── always-on.md           # 技术硬约束(始终生效)
    ├── agent-workflow.md      # AI Agent 工作流约束
    ├── java-code-style.md     # Java 代码风格规则
    └── java-testing.md        # 测试规则

共 4 个文件 ,全部位于 .qoder/rules/ 目录下。


3. 逐个文件编写指南

3.1 always-on.md --- 技术硬约束

定位

这是最核心的规则文件。AI Agent 在生成任何代码时都会参考此文件。每一条规则都是"违反即必须修正"的硬性约束。

编写策略:从架构基线推导规则

Step 1 中你定义了架构基线(技术栈、模块边界、数据流转)。现在将这些基线转化为可执行的规则:

复制代码
架构基线(Step 1)              →    硬性规则(本步)
──────────────────────                ──────────────────
overview.md 技术栈表                 →  第 1 节:技术栈锁定
boundaries.md 依赖方向图             →  第 2 节:模块依赖方向
overview.md 技术选型(HTTP/JSON)    →  第 4~5 节:日志/HTTP 规范
boundaries.md 跨模块约束             →  第 6 节:数据库访问
data-flow.md 跨线程传播              →  第 9 节:traceId 传播
建议包含的约束条目(按编号)
编号 约束名 核心内容 推导来源
1 技术栈锁定 锁定 JDK/框架/库版本,禁止升级 overview.md 技术栈表
2 模块依赖方向 依赖只能向上流动 boundaries.md 依赖方向图
3 依赖注入 优先 @Resource,禁止字段级 @Autowired 通用最佳实践
4 日志规范 @Slf4j,占位符格式 通用最佳实践
5 HTTP 调用 统一 HTTP 客户端 overview.md 技术选型
6 数据库访问 统一访问方式 boundaries.md 跨模块约束
7 线程池 统一线程池工厂 通用最佳实践
8 限流 统一限流框架 overview.md 技术选型
9 traceId 传播 跨线程显式传递 data-flow.md 跨线程传播
10 事务 编程式事务 通用最佳实践
11 配置管理 配置中心统一管理 overview.md 配置中心
12 注释语言 中文注释 团队约定
13 代码行数限制 单文件 ≤ 300 行,单方法 ≤ 80 行 阿里规范
编写模板
markdown 复制代码
# Always-On Rules

这些规则在所有任务中始终生效,AI Agent 必须严格遵守。

## 1. 技术栈锁定

- JDK 1.8:禁止使用 var、record、text block 等 Java 9+ 语法
- Spring Boot {版本}:禁止升级到 3.x
- {JSON 库} {版本}:禁止引入其他 JSON 库
{...}

## 2. 模块依赖方向

依赖只能向上流动,严禁反向依赖或跨层引用:

{ASCII 依赖方向图}

- {模块 A} 不允许依赖任何项目内模块
- {模块 B} 只能依赖 {模块 A}
{...}

## 3. 依赖注入

- 优先使用 @Resource
- 新代码推荐构造器注入
- 禁止字段级 @Autowired 扩散

## 4. 日志规范

- 统一使用 Lombok @Slf4j,禁止 LoggerFactory.getLogger()
- 禁止 System.out.println() 和 e.printStackTrace()
- 日志使用占位符格式:log.error("描述,param={}", param, e)
- 禁止字符串拼接日志

## 5. HTTP 调用

- 统一使用 {HTTP 客户端} + {工厂类}
- 禁止直接 new {HTTP 客户端}
- 禁止使用其他 HTTP 客户端

## 6. 数据库访问

- 必须通过 {统一访问方式} 获取 Manager 实例
- 禁止直接注入 Mapper
- Entity 使用 @TableName + @Data + @Builder + @TableId(type = IdType.AUTO),字段使用 @TableField 映射蛇形列名
- 逻辑删除使用 yn 字段(0=有效, 1=删除)

## 7. 线程池

- 使用 {线程池工厂}({模块路径})
- 禁止裸 new ThreadPoolExecutor

## 8. 限流

- 使用 {限流框架}
- 禁止自行实现限流逻辑

## 9. traceId 传播

- 主线程使用 {注解} 注入 traceId
- 子线程使用 {工具类} 显式传递 traceId
- 禁止在线程切换时丢失 traceId 上下文

## 10. 事务

- 使用 {编程式事务工具}
- 禁止使用 @Transactional 注解
- 事务内异常必须 setRollbackOnly() + 返回 false

## 11. 配置管理

- 配置统一走 {配置中心}(namespace: dev1 / test1 / pre / prod)
- 禁止硬编码环境地址、数据库连接、密钥

## 12. 注释语言

- 类/方法/字段注释使用中文
- 注释需说明业务含义,禁止无意义注释
编写要点
  1. 每条规则用"必须 / 禁止"的祈使句:AI Agent 对祈使句的遵守率远高于陈述句
  2. 给出正面和反面示例:如日志规则同时写"正确:占位符格式"和"错误:字符串拼接"
  3. 标注推导来源:在注释中标注此规则来自哪个架构文档,便于后续维护
  4. 控制在 100~120 行:规则太多会导致 AI 上下文膨胀
实际示例
markdown 复制代码
---
last_updated: 2026-06-29
status: active
owner: @zhangsan
---
# Always-On Rules

这些规则在所有任务中始终生效,AI Agent 必须严格遵守。

## 1. 技术栈锁定

- JDK 1.8:禁止使用 var、record、text block、switch yield、Stream.toList() 等 Java 9+ 语法
- Spring Boot 2.3.12.RELEASE:禁止升级到 3.x,禁止使用 Spring 6 的jakarta包名
- MyBatis-Plus 3.4.3:禁止使用 3.5+ 的静态链式查询等新 API
- FastJSON 1.2.83:JSON 序列化/反序列化统一使用 com.alibaba.fastjson.JSON,禁止引入 Jackson / Gson
- OkHttp 3.14.9:统一 HTTP 客户端(详见第 5 节)
- Lombok 1.18.12:统一注解处理器
- MapStruct 1.5.2.Final:DTO 转换统一使用 MapStruct,禁止手写 convert 方法
- XXL-JOB 2.2.0:分布式调度框架

## 2. 模块依赖方向

依赖只能向上流动,严禁反向依赖或跨层引用:

\```
common → dal → business → ext → app → runner
common → dal → business → ext → soa-service → app-soa → deploy-set
\```

- exchange-common 不允许依赖任何项目内模块
- exchange-dal 只能依赖 exchange-common
- exchange-business 只能依赖 exchange-dal + exchange-common
- exchange-ext 子模块只能依赖 exchange-business,ext 子模块之间禁止互相依赖
- exchange-app 依赖全部 ext 子模块
- exchange-runner 依赖 exchange-app
- exchange-api 独立发布,仅依赖 Lombok

## 3. 依赖注入

- 优先使用 @Resource(javax.annotation.Resource)
- 新代码推荐构造器注入
- 禁止字段级 @Autowired 扩散
- 禁止在构造器中使用 @Autowired(Spring 4.3+ 单构造器自动注入)
- 例外:DAL 层 BaseManager 泛型基类的 Mapper 注入(泛型类型由子类决定,@Resource 不支持泛型推断)

## 4. 日志规范

- 业务代码统一使用 Lombok @Slf4j,禁止 LoggerFactory.getLogger()
- 例外:exchange-common 基础设施层需要命名 Logger 的场景(如 "BatchExecutor"、"RateLimit"、"MDC"),@Slf4j 以类名为 Logger 名无法满足跨类统一命名
- 例外:DAL 层 BaseManager 继承 MyBatis-Plus 框架,使用 LogFactory.getLog(getClass())
- 禁止 System.out.println() 和 e.printStackTrace()
- 日志使用占位符格式:log.error("描述,planId={}", planId, e)
- 禁止字符串拼接日志:log.error("planId:" + planId)

## 5. HTTP 调用

- 统一使用 OkHttp3 3.14.9 + HttpClientFactory(exchange-common/http)
- 禁止直接 new OkHttpClient()
- 禁止使用 RestTemplate / HttpURLConnection / Apache HttpClient
- 例外(历史债务):FeiShuNoticeProcessor 自建 OkHttpClient.Builder()。HttpClientFactory 已支持自定义超时/连接池配置(通过 HttpConfig),新通知组件必须使用 HttpClientFactory.getOrBuildOkHttpClient(),禁止重复此例外

## 6. 数据库访问

- 必须通过 DalManager.of(beanName) 获取 Manager 实例
- 禁止直接注入 Mapper
- Entity 使用 @TableName + @Data + @Builder + @TableId(type = IdType.AUTO),字段使用 @TableField 映射蛇形列名
- 逻辑删除使用 yn 字段(0=有效, 1=删除)

## 7. 线程池

- 使用 BatchExecutorTemplate / ThreadPoolExecutorBuilder(exchange-common/juc)
- 禁止裸 new ThreadPoolExecutor / new ForkJoinPool / CompletableFuture.supplyAsync 无自定义线程池

## 8. 限流

- 使用 Resilience4j + RateLimitFactory(exchange-common/sentinel/limit)
- 禁止自行实现限流逻辑

## 9. traceId 传播

- 主线程使用 @MDC(types = {TraceType.TIMER, TraceType.LOG}) 注解
- 子线程使用 ContextHolder / MDCTemplate 显式传递 traceId
- 禁止在线程切换时丢失 traceId 上下文

## 10. 事务

- 使用 TransactionTemplate 编程式事务
- 事务内异常必须 transaction.setRollbackOnly() + 返回 false
- 禁止使用 @Transactional 注解(与动态数据源不兼容)
- 例外:DAL 层 BaseManager 继承 MyBatis-Plus IService 的批量操作方法(saveBatch/saveOrUpdate/updateBatchById),使用 @Transactional 是框架标准实现

## 11. 配置管理

- 配置统一走 Nacos(namespace: dev1 / test1 / pre / prod)
- 禁止硬编码环境地址、数据库连接、Redis 地址
- 禁止在代码中写入密钥、token、密码

## 12. 注释语言

- 类/方法/字段注释使用中文
- 注释需说明业务含义,禁止无意义注释

## 13. 代码行数限制(阿里规范)

遵循《阿里巴巴 Java 开发手册》编码规约:

- 单个 .java 文件总行数 ≤ 300 行(含注释和空行)
- 单个方法体行数 ≤ 80 行(不含方法签名和注解)
- 超过限制时必须拆分:文件按职责拆分为多个类,方法按逻辑拆分为多个私有方法
- 禁止通过减少注释或空行来人为压缩行数

> 自动化层门禁规则已迁移至 `agent-workflow.md` 第 8 节(避免重复定义浪费 token)

3.2 agent-workflow.md --- AI Agent 工作流约束

定位

约束 AI Agent 的开发流程行为 ,确保 PRD → 设计 → 编码全链路可控。与 always-on.md 互补:前者约束"代码怎么写 ",后者约束"流程怎么走"。

必须包含的章节
章节 内容 核心约束
1. 强制流程顺序 PRD 到交付的完整步骤 禁止跳步
2. 技术设计文档要求 设计文档的格式和保存位置 必须基于模板生成
3. 设计评审门禁 评审通过后才能写代码 人工确认门禁
4. 按需加载策略 每步加载哪些文档 禁止预读后续步骤
5. 代码生成约束 代码生成的顺序和规范 自底向上生成
6. 交付前自检 交付前的检查要求 禁止跳过自检
7. 文档同步 代码变更后同步哪些文档 必须同步
8. 自动化层自我验证 编译/测试/治理的客观验证 客观数据优先
关键设计:强制流程顺序
markdown 复制代码
## 1. 强制流程顺序

PRD 驱动开发必须按以下顺序执行,禁止跳步:
Step 0: 环境检查与输入校验(BRD→PRD + PRD 完整性)
  → Step 1: PRD 解析 → Step 2: 影响分析 → Step 3: 技术设计文档
  → Step 4: 设计评审(门禁)→ Step 5: 代码生成 → Step 5.5: 编译验证(门禁)
  → Step 6: 配置与文档同步 → Step 7: 自动治理巡检 + PR 自检 → 交付

- 禁止跳过环境检查与输入校验直接开始 PRD 解析
- 禁止跳过 PRD 解析直接进行影响分析
- 禁止跳过影响分析直接生成技术设计文档
- 禁止跳过技术设计文档直接写代码
- 禁止跳过设计评审直接生成代码
- 禁止跳过编译验证直接配置同步
- 禁止跳过自动治理巡检直接自检
- 禁止跳过自检直接交付
关键设计:人工确认门禁

这是 Harness Engineering 的核心理念------"AI 生成,人类驾驭"。在设计评审环节设置人工门禁:

markdown 复制代码
## 3. 设计评审门禁

**⚠️ 人工确认门禁**:
- 评审完成后,必须将设计文档摘要 + 评审报告输出给用户
- **必须暂停等待用户明确确认**(「通过」/「需要修改」/「重新设计」)
- 禁止在未获得用户确认前自动进入代码生成阶段
- 评审通过后将设计文档 `status` 改为 `active`
关键设计:按需加载策略

为避免 AI 上下文膨胀,每个步骤只加载该步骤所需的文档:

markdown 复制代码
## 4. 按需加载策略

### 始终加载(IDE 自动注入,不占额外 token)
- .qoder/rules/*.md(4 个文件)

### 分步按需加载
| 步骤 | 按需加载 | 预估 token |
|------|---------|------------|
| Step 0 环境检查 | pre-check.ps1 + prd-template.md §0 + brd-to-prd-guide.md(如 BRD) | ~400~1600 |
| Step 1 PRD解析 | AGENTS.md + prd-template.md + code-assets.md | ~2000 |
| Step 2 影响分析 | boundaries.md + impact-analysis.md | ~1500~3500 |
| Step 3 设计文档 | _template.md + data-flow.md | ~3000 |
| Step 4 设计评审 | design-review.md | ~1000 |
| Step 5 代码生成 | 按需触发 add-*.md | ~800 |
| Step 5.5 编译验证 | 无需加载文档 | 0 |
| Step 6 文档同步 | error-codes.md + api.spec.yaml | ~1500 |
| Step 7 自检 | auto-governance.md + pr-checklist.md | ~1600 |

### 加载规则
1. 禁止在 Step 1 预读后续步骤文档
2. 每步完成后可释放前序步骤的文档上下文
3. 单步加载总量控制在 3000 token 以内
编写要点
  1. 流程顺序是铁律:用"禁止跳步"的措辞,不要用"建议按序"
  2. 门禁要明确:写清楚"暂停等待用户确认"的动作,防止 AI 自行跳过
  3. 按需加载表要精确:每步标注预估 token,帮助 AI 理解加载边界
  4. 文档同步表要完整:列出所有变更类型和对应的需更新文档
实际实例
markdown 复制代码
---
last_updated: 2026-06-29
status: active
owner: @zhangsan
---
# AI Agent 工作流规则

这些规则约束 AI Agent 的开发流程行为,确保 PRD → 设计 → 编码全链路可控。

## 1. 强制流程顺序

PRD 驱动开发必须按以下顺序执行,禁止跳步:

\```
Step 0: 环境检查与输入校验(BRD→PRD + PRD 完整性)
  → Step 1: PRD 解析与上下文加载
  → Step 2: 影响分析
  → Step 3: 技术设计文档
  → Step 4: 设计评审(门禁)
  → Step 5: 代码生成
  → Step 5.5: 即时编译验证(门禁)
  → Step 6: 配置与文档同步
  → Step 7: 自动治理巡检 + PR 自检
  → 交付
\```

- 禁止跳过环境检查与输入校验直接开始 PRD 解析
- 禁止跳过 PRD 解析直接进行影响分析
- 禁止跳过影响分析直接生成技术设计文档
- 禁止跳过技术设计文档直接写代码
- 禁止跳过设计评审直接生成代码
- 禁止跳过即时编译验证直接配置同步
- 禁止跳过自动治理巡检直接自检
- 禁止跳过自检直接交付

## 2. 技术设计文档要求

- 必须基于 `docs/design/_template.md` 模板生成
- 生成后保存到 `docs/design/feature-{功能名}.md`
- 初始 `status` 设为 `draft`
- 必须包含:目标、范围、关联文档、分层设计、数据库约束、API约定、配置项、测试要求、风险与对策、自检清单
- 必须引用 PRD 来源路径
- 必须列出关联的影响分析(参考 `docs/changes/impact-analysis.md`)

## 3. 设计评审门禁

代码生成前,必须完成设计评审(参考 `.qoder/skills/design-review.md`),并**通过人工确认后**方可进入代码生成阶段:

- 模块归属是否正确(不能违反依赖方向)
- 类设计是否复用已有基类和接口
- 数据库表设计是否符合命名规范(tb_ 前缀、yn 字段、create_time/update_time)
- API 设计是否需要更新 `api.spec.yaml`
- 错误码是否需要新增并登记到 `error-codes.md`
- 测试方案是否覆盖正常/异常/边界场景

**⚠️ 人工确认门禁**:
- 评审完成后,必须将设计文档摘要 + 评审报告输出给用户
- **必须暂停等待用户明确确认**(「通过」/「需要修改」/「重新设计」)
- 禁止在未获得用户确认前自动进入代码生成阶段
- 评审通过后将设计文档 `status` 改为 `active`

## 4. 按需加载策略(节省 token)

### 4.1 始终加载(IDE 自动注入,不占额外 token)

以下文件由 IDE 自动加载到 Agent 上下文,无需手动读取:

- `.qoder/rules/always-on.md`
- `.qoder/rules/agent-workflow.md`(本文件)
- `.qoder/rules/java-code-style.md`
- `.qoder/rules/java-testing.md`

### 4.2 分步按需加载(Agent 按步骤读取,禁止一次性全量加载)

Agent 在执行 `prd-to-code` 技能时,**每个 Step 只加载该步骤所需文档**,禁止在 Step 1 预读后续步骤的文档:

| 步骤 | 按需加载 | 目的 | 预估 token |
|------|---------|------|------------|
| Step 0 环境检查 | `build/automation/scripts/pre-check.ps1` + `worktree-manager.ps1` + `docs/reference/prd-template.md` 第 0 节 + **条件:`docs/reference/brd-to-prd-guide.md`(仅输入为 BRD 时)** | 环境校验 + Worktree 创建 + BRD→PRD 转换 + PRD 完整性校验 | ~400~1600 |
| Step 1 PRD解析 | `AGENTS.md` + `docs/reference/prd-template.md` + `docs/architecture/code-assets.md` + 知识卡 | 项目基线 + PRD格式 + 代码资产 + 模块知识 | ~2000 |
| Step 2 影响分析 | `docs/architecture/boundaries.md` + `docs/changes/impact-analysis.md` + **条件:`docs/reference/api.spec.yaml`(仅 PRD 涉及 API 变更时读取相关段)** | 模块边界 + 影响分析模板 + 现有API契约 | ~1500~3500 |
| Step 3 设计文档 | `docs/design/_template.md` + `docs/architecture/data-flow.md` + 1~2个相关 `feature-*.md` | 设计模板 + 数据流 + 相似设计参考 | ~3000 |
| Step 4 设计评审 | `.qoder/skills/design-review.md`(斜杠命令触发) | 7维度评审检查 | ~1000 |
| Step 5 代码生成 | 按需触发相关 `.qoder/skills/add-*.md`(如需新增供应商/Entity/API) | 具体操作手册 | ~800 |
| Step 5.5 编译验证 | 无需加载文档 | 即时编译检查 | 0 |
| Step 6 文档同步 | `docs/reference/error-codes.md` + `docs/reference/api.spec.yaml`(全量读取,写入新API段) | 同步错误码与API | ~1500 |
| Step 7 自检(含自动治理门禁) | `.qoder/skills/auto-governance.md` + `docs/changes/pr-checklist.md` | 自动治理巡检 + PR检查清单 | ~1600 |

### 4.3 加载规则

- 禁止在 Step 1 预读 Step 2~7 的文档
- 每个 Step 完成后,可释放前序步骤的文档上下文(无需保持)
- 如某 Step 发现需要回溯前序文档,按需补读即可
- Rules 层始终在上下文中(IDE 自动注入),不计入按需加载
- Skills 层仅在对应 Step 触发时加载
- 单个 Step 的按需加载总量控制在 3000 token 以内

## 5. 代码生成约束

- 必须严格遵守 `.qoder/rules/` 下的全部规则文件
- 必须按模块依赖方向自底向上生成:
  - Web 链路:dal → business → ext → app → runner
  - SOA 链路:dal → business → ext → soa-service → app-soa → deploy-set
- 每个新增 Java 文件必须有中文类注释 + @author 标注
- 必须同步生成 JUnit 5 + Mockito 单元测试
- 必须同步更新受影响的文档(error-codes.md / api.spec.yaml / CHANGELOG.md)
- **代码生成完成后必须执行自动治理巡检**(见第 8 节),禁止直接进入自检

## 6. 交付前自检

代码生成完成后,必须先执行自动治理巡检(第 8 节),再执行 `docs/changes/pr-checklist.md` 中的全部检查项,逐项确认通过后方可交付。

**顺序要求**:自动治理巡检 → PR 自检清单。禁止跳过自动治理巡检直接执行 PR 自检清单。

## 7. 文档同步

每次代码变更必须同步更新:

| 变更类型 | 需更新的文档 |
|---------|-------------|
| 新增/修改错误码 | docs/reference/error-codes.md |
| 新增/修改 API | docs/reference/api.spec.yaml |
| 新增功能 | docs/design/feature-{name}.md + CHANGELOG.md |
| 修改模块结构 | docs/architecture/boundaries.md |
| 修改数据流转 | docs/architecture/data-flow.md |
| 新增 SOA 服务 | exchange-deploy-set/exchange-soa-runner/.../spring/spring-dubbo-provider.xml(Dubbo 服务暴露配置) |
| 新增/删除 .md / .yaml / .ps1 / .xml 文件 | docs/ai-coding-guide.md §5 文档全景索引(同步新增/删除文件条目) |

> **全景索引同步规则**:凡是在 `.qoder/rules/`、`.qoder/skills/`、`docs/`、`build/automation/scripts/`、`build/linter/` 目录下新增或删除 .md/.yaml/.ps1/.xml 文件时,
> **必须同步更新** `docs/ai-coding-guide.md` 第 5 节「文档全景索引」中对应的文件树。
> 可运行 `build/automation/scripts/index-sync-check.ps1` 验证索引一致性。

## 8. 自动化层自我验证(强制)

代码生成完成后、PR 自检前,Agent **必须**执行自我验证,基于客观数据决策而非主观判断:

### 8.1 强制巡检

- 必须执行 `/auto-governance`(或手动运行 `collect-sidecar.ps1` + `decay-detector.ps1`)
- 必须读取 `build/automation/sidecar/sidecar-summary.json` 获取客观数据
- 禁止仅凭读代码做"应该没问题"的主观判断后直接交付

### 8.2 门禁阻断规则

| 条件 | 动作 |
|------|------|
| `build-status.json` 中 `compileSuccess = false` | **禁止交付**,返回修复编译错误 |
| `test-results.json` 中 `failed > 0` | **禁止交付**,返回修复失败测试 |
| `decay-report.json` 中 `overallScore < 60` | **需人工确认**后方可交付 |
| `sidecar-summary.json` 不存在或 `timestamp` 超过 24 小时 | 必须重新采集后再交付 |

### 8.3 客观侧性优先原则

当 Agent 的主观判断与 sidecar JSON 客观数据冲突时,以客观数据为准:
- Agent 认为"代码没问题"但 `build-status.json` 显示编译失败 → 以客观数据为准,修复编译错误
- Agent 认为"测试应该通过"但 `test-results.json` 显示失败 → 以客观数据为准,修复失败测试

3.3 java-code-style.md --- Java 代码风格

定位

约束 Java 代码的包结构、命名、注解使用和异常处理 。与 always-on.md 互补:前者是"技术选型约束",后者是"代码风格约束"。

必须包含的章节
章节 内容
包结构 每个模块的包前缀规则
类命名 各类型类的后缀/前缀规则
Lombok 使用 哪些注解用在哪里
异常处理 catch 块的处理规范、Controller 异常约定
import 规范 禁止通配符 import
供应商扩展 新增供应商的代码规范
编写模板
markdown 复制代码
# Java 代码风格规则

适用于所有 `.java` 文件。

## 包结构

| 层 | 包前缀 | 示例 |
|----|--------|------|
| common | `com.{org}.{模块}` | `com.jzsk.trace` |
| dal | `com.{org}.exchange.dal.{子层}` | `com.jzsk.exchange.dal.entity` |
| business | `com.{org}.exchange.{子域}` | `com.jzsk.exchange.core.async` |
| ext | `com.{org}.exchange.ext.{供应商缩写}` | `com.jzsk.exchange.ext.tc` |

## 类命名

| 类型 | 后缀/前缀 | 示例 |
|------|----------|------|
| Entity | 无特殊后缀 | `SourceData` |
| Mapper | `*Mapper` | `SourceDataMapper` |
| Manager | `*Manager` | `SourceDataManager` |
| Processor | `*Processor` | `AsyncProcessor` |
| Trigger | `*Trigger` | `PlanLifecycleTrigger` |
| Scheduler | `*Scheduler` | `AsyncScheduler` |
| Service | `*Service` | `SyncSingleService` |
| Convertor | `*Convertor` | `TCInputConvertor` |
| Parser | `*HttpResultParser` | `TCHttpResultParser3605` |
| Config | `*Config` | `BizConfiguration` |
| DTO | `*DTO` | `RequestDTO` |
| Context | `*Context` | `AsyncContext` |
| Event | `*Event` | `FileRecordEvent` |
| Enum | `*Enum` | `CodeEnum` |

## Lombok 使用

- Entity / DTO:@Data
- 日志类:@Slf4j
- 构造器:@Builder + @Builder.Default
- @SneakyThrows 仅限 Scheduler / Trigger 等框架适配场景
- Entity / DTO 禁止用 @AllArgsConstructor + @NoArgsConstructor 替代 @Data
- Event / Enum / Context 等不可变值对象允许使用 @AllArgsConstructor

## 异常处理

- catch 块必须记录日志或向上抛出,禁止空 catch
- 异常日志格式:log.error("描述,param={}", param, e)
- 业务异常返回错误码,不抛异常
- Controller 层必须 try-catch
- 不使用 @ControllerAdvice,每个 Controller 方法手动 try-catch

## import 规范

- 禁止通配符 import(import xxx.*),必须逐个导入
编写要点
  1. 命名规则要给出正反示例 :如 "✅ SourceDataManager,❌ SourceDataServiceImpl"
  2. 供应商前缀规则要明确 :如 "天创用 TC*,友盟用 Ym*"
  3. 控制在 50~60 行:代码风格规则不宜太长,AI 需要快速匹配
实际实例
markdown 复制代码
---
last_updated: 2026-06-29
status: active
owner: @zhangsan
---
# Java 代码风格规则

适用于所有 `.java` 文件。

## 包结构

- common 模块包前缀:`com.jzsk.{模块}`
- dal 模块包前缀:`com.jzsk.exchange.dal.{子层}`
- business 模块包前缀:`com.jzsk.exchange.{子域}`
- ext 模块包前缀:`com.jzsk.exchange.ext.{供应商缩写}`
- app 模块包前缀:`com.jzsk.exchange.app.{子域}`
- runner 模块包前缀:`com.jzsk.exchange` / `com.jzsk.exchange.controller`
- soa 模块包前缀:`com.jzsk.exchange.soa.service`

## 类命名

- Entity:无特殊后缀,如 `SourceData`
- Mapper:`*Mapper`,如 `SourceDataMapper`
- Manager:`*Manager`,如 `SourceDataManager`
- Processor:`*Processor`,如 `AsyncProcessor`
- Trigger:`*Trigger`,如 `PlanLifecycleTrigger`
- Scheduler:`*Scheduler`,如 `AsyncScheduler`、`ShardingScheduler`
- Service:`*Service`,如 `SyncSingleService`、`AdminService`
- Delegate:`*Delegate`,如 `HttpJsonPostRateLimitDelegate`
- Convertor:`*Convertor`,如 `TCInputConvertor`
- Parser:`*Parser` / `*HttpResultParser`,如 `TCHttpResultParser3605`
- Strategy:`*Strategy`,如 `HttpResultParserStrategy`
- Facade:`*Facade`,如 `CommonQueryFacade`
- Config:`*Config` / `*Configuration`
- DTO:`*DTO`,如 `RequestDTO`
- Context:`*Context`,如 `AsyncContext`
- Event:`*Event`,如 `FileRecordEvent`、`NoticeAfterEvent`
- Enum:`*Enum`,如 `CodeEnum`、`YesOrNoEnum`
- Constants:`Constants`(放在对应模块根包),如 `com.jzsk.exchange.ext.tc.Constants`
- 供应商适配类加前缀:`TC*` / `Ym*` / `Bh*`
- 接口解析器带接口编号:`TCHttpResultParser3605`(天创 3605 接口)
- 详细方法命名/数据库命名/常量命名参见 `docs/conventions/naming.md`

## Lombok 使用

- Entity / DTO:`@Data`
- 日志类:`@Slf4j`
- 构造器:`@Builder` + `@Builder.Default`
- 异常包装:`@SneakyThrows`(仅限 Scheduler / Trigger 等需适配 XXL-JOB / Spring 框架签名的场景,禁止在 business 层核心逻辑中使用)
- Entity / DTO 禁止用 `@AllArgsConstructor` + `@NoArgsConstructor` 替代 `@Data`
- Event / Enum / Context 等不可变值对象允许使用 `@AllArgsConstructor`(非替代 @Data,而是需要全参构造器)

## 异常处理

- catch 块必须记录日志或向上抛出,禁止空 catch
- 异常日志格式:`log.error("描述,param={}", param, e)` --- 异常对象放最后一个参数
- 业务异常返回错误码(CodeEnum),不抛异常
- 系统异常 catch 后返回 CodeEnum.UNKNOWN
- Controller 层必须 try-catch,禁止异常暴露给调用方
- 项目不使用 `@ControllerAdvice` / `@ExceptionHandler`,每个 Controller 方法手动 try-catch
- REST API 用 `@RestController`,页面渲染用 `@Controller`

## import 规范

- 禁止通配符 import(`import xxx.*`),必须逐个导入

## 供应商扩展

- 新增供应商必须在 exchange-ext 下新建子模块
- 子模块必须继承 business 中的抽象基类:InputConvertor / HttpResultParser / PortResultConvertor
- 供应商配置必须在 BizConfiguration.preInitAppConfig() 中注册到 PortConfigFactory / PlanConfigFactory
- 使用 putIfAbsent 注册,禁止覆盖已有配置

3.4 java-testing.md --- 测试规则

定位

约束测试代码的分类、框架选择、命名、Mock 策略和覆盖要求。区分单元测试与集成测试,确保单元测试可独立运行、不依赖外部环境,同时为集成测试和架构测试留出合理空间。

必须包含的章节
章节 内容
测试分类 单元测试 / 集成测试 / 架构测试,明确各自适用规则
框架 JUnit 5 + Mockito + ArchUnit,禁止 JUnit 4(含 @RunWithorg.junit.Assert.*
命名 单元测试 {被测类}Test.java,集成测试 {被测类}IntegrationTest.java,推荐 @DisplayName + @Nested
Mock 策略 静态方法 mockStatic、依赖 @Mock + @InjectMocks、@MockitoSettings
集成测试规则 @RunWithSpring + @Resource 注入,允许外部依赖
架构测试规则 ArchUnit @AnalyzeClasses + @ArchTest,失败消息含三要素
覆盖要求 正常路径、参数校验失败、异常路径、边界条件
禁止项(单元测试) 禁止 new Spring Context、禁止外部依赖、禁止 Thread.sleep、禁止 JUnit 4 导入
编写模板
markdown 复制代码
# 测试规则

适用于所有 `*Test.java` 和 `Test*.java` 文件。

## 测试分类

| 类型 | 所在模块 | 核心注解 | Spring 上下文 | 外部依赖 |
|------|---------|---------|-------------|---------|
| 单元测试 | {业务模块} | `@ExtendWith(MockitoExtension.class)` | 禁止 | 禁止 |
| 集成测试 | {集成测试模块} | `{项目自定义 Spring 注解}` | 允许 | 允许 |
| 架构测试 | {架构测试模块} | `@AnalyzeClasses` + `@ArchTest` | 不需要 | 不需要 |

## 框架

- 测试框架:JUnit 5 (Jupiter {版本})
- Mock 框架:Mockito {版本}(含 mockito-inline 支持静态方法 Mock)
- 架构测试:ArchUnit {版本}
- 禁止使用 JUnit 4 的 `@RunWith` 注解
- 禁止导入 `org.junit.Assert.*`,必须使用 `org.junit.jupiter.api.Assertions.*`

## 命名

- 单元测试类:`{被测类名}Test.java`,与被测类同包
- 集成测试类:`{被测类名}IntegrationTest.java`,与被测类同包
- 推荐使用 `@DisplayName` + `@Nested` 分组

## Mock 策略(单元测试)

- `{项目数据访问入口}`:必须 `mockStatic()` + `when().thenAnswer()`
- 依赖:`@Mock` + `@InjectMocks`
- 需要部分真实行为:`@Spy` 替代 `@Mock`

## 集成测试规则

- 使用项目自定义注解启动 Spring 上下文
- 允许依赖外部环境

## 架构测试规则

- ArchUnit 校验模块依赖方向
- 失败消息包含三要素:问题 / 修复 / 文档路径

## 覆盖要求

- 正常路径、参数校验失败、异常路径、边界条件
- 新增代码行覆盖率 >= 95%

## 禁止(单元测试)

- 禁止 new Spring ApplicationContext
- 禁止依赖外部环境运行单元测试
- 禁止 `Thread.sleep()` 等待异步结果
- 禁止导入 JUnit 4 的 `org.junit.Assert.*`
编写要点
  1. 区分测试类型是关键:单元测试禁止外部依赖,集成测试允许,架构测试不需要 Spring 上下文
  2. Mock 策略要具体到方法级别 :如 DalManager.of() 必须用 mockStatic + when().thenAnswer()
  3. 集成测试用项目自定义注解@RunWithSpring 而非 @MockBean,与项目实际一致
  4. 禁止项明确限定单元测试:标题写"禁止(单元测试)",避免集成测试被误判违规
  5. 覆盖要求可量化:如"行覆盖率 >= 95%",便于后续自动化层检测
实际实例
markdown 复制代码
---
last_updated: 2026-06-29
status: active
owner: @zhangsan
---
# 测试规则

适用于所有 `*Test.java` 和 `Test*.java` 文件。

## 测试分类

项目区分两类测试,适用不同规则:

| 类型 | 所在模块 | 核心注解 | Spring 上下文 | 外部依赖 |
|------|---------|---------|-------------|---------|
| 单元测试 | exchange-common/dal/business/ext/app/runner/soa-service | `@ExtendWith(MockitoExtension.class)` | ❌ 禁止 | ❌ 禁止 |
| 集成测试 | exchange-test、exchange-deploy-set | `@RunWithSpring` | ✅ 允许 | ✅ 允许 |
| 架构测试 | exchange-test | `@AnalyzeClasses` + `@ArchTest` | ❌ 不需要 | ❌ 不需要 |

## 框架

- 测试框架:JUnit 5 (Jupiter 5.6.3)
- Mock 框架:Mockito 3.12.4(含 mockito-inline 支持静态方法 Mock)
- 架构测试:ArchUnit 0.23.1(archunit-junit5)
- 单元测试注解:`@ExtendWith(MockitoExtension.class)`
- 禁止使用 JUnit 4 的 `@RunWith` 注解
- 禁止导入 `org.junit.Assert.*`,必须使用 `org.junit.jupiter.api.Assertions.*`

## 命名

- 单元测试类:`{被测类名}Test.java`,与被测类同包
- 集成测试类:`{被测类名}IntegrationTest.java`,与被测类同包
- 测试方法:`test{场景描述}()` 或 `test{被测方法}_{条件}()`
- 推荐使用 `@DisplayName("中文场景描述")` 增强可读性
- 推荐使用 `@Nested` 对测试方法分组(如:参数校验/正常流程/异常路径/边界条件)
- 参数化测试使用 `@ParameterizedTest`

## Mock 策略(单元测试)

- `DalManager.of(beanName)`:必须 `mockStatic(DalManager.class)` + `when().thenAnswer()`
- Manager / Service 依赖:`@Mock` + `@InjectMocks`
- 需要部分真实行为:`@Spy` 替代 `@Mock`
- 静态方法 Mock:使用 `mockStatic()`(try-with-resources 或 `@BeforeEach` open / `@AfterEach` close)
- 严格模式默认开启,如需宽松匹配:`@MockitoSettings(strictness = Strictness.LENIENT)`

## 集成测试规则

- 使用项目自定义 `@RunWithSpring` 注解启动 Spring 上下文
- 依赖注入使用 `@Resource`
- 允许依赖外部 Nacos / Redis / MySQL 环境
- 允许使用 `Thread.sleep()` 模拟时间流逝(限流/超时场景)

## 架构测试规则

- 使用 ArchUnit(`@AnalyzeClasses` + `@ArchTest`)
- 位于 exchange-test 模块,校验模块依赖方向不可逆
- 失败消息必须包含三要素:问题 / 修复 / 文档路径

## 覆盖要求

新功能必须有单元测试,覆盖以下场景:
- 正常路径
- 参数校验失败(空值、非法值)
- 异常路径(catch 分支)
- 边界条件(空集合、null 返回)
- 新增代码行覆盖率>=95%

## 禁止(单元测试)

- 禁止测试方法中直接 new Spring ApplicationContext(使用 Mockito 替代)
- 禁止依赖外部 Nacos / Redis / MySQL 环境运行单元测试
- 禁止使用 `Thread.sleep()` 等待异步结果(使用 CountDownLatch 或同步执行)
- 禁止导入 JUnit 4 的 `org.junit.Assert.*`(使用 `org.junit.jupiter.api.Assertions.*`)

4. Rules 层设计原则

4.1 祈使句原则

每条规则使用"必须 / 禁止"的祈使句,而非陈述句:

❌ 陈述句 ✅ 祈使句
日志推荐使用 @Slf4j 统一使用 @Slf4j,禁止 LoggerFactory.getLogger()
建议通过 DalManager 访问 必须通过 DalManager.of() 获取,禁止直接注入 Mapper
尽量避免 @Transactional 禁止使用 @Transactional 注解

4.2 正反示例原则

每条规则同时给出"正确做法"和"错误做法":

markdown 复制代码
- 日志使用占位符格式:log.error("描述,param={}", param, e)  ← ✅ 正确
- 禁止字符串拼接日志:log.error("param:" + param)            ← ❌ 错误

4.3 可验证原则

规则必须是可通过 Linter 或人工检查验证的:

❌ 不可验证 ✅ 可验证
代码要写得好 单文件 ≤ 300 行
注释要有意义 每个 Java 文件必须有中文类注释 + @author
异常处理要合理 catch 块必须记录日志或向上抛出,禁止空 catch

4.4 推导可追溯原则

每条规则标注推导来源,便于后续维护和更新:

markdown 复制代码
## 2. 模块依赖方向
<!-- 推导来源: docs/architecture/boundaries.md 依赖方向图 -->
依赖只能向上流动...

5. 完成验证清单

完成本步后,逐项检查:

  • .qoder/rules/always-on.md 存在,包含 13 条硬性约束(技术栈/依赖方向/注入/日志/HTTP/数据库/线程池/限流/traceId/事务/配置/注释/代码行数限制)
  • .qoder/rules/agent-workflow.md 存在,包含强制流程顺序(含 BRD→PRD)、设计评审门禁、按需加载策略、代码生成约束、交付前自检、文档同步、自动化层自我验证
  • .qoder/rules/java-code-style.md 存在,包含包结构、类命名、Lombok 使用、异常处理、import 规范、供应商扩展规范
  • .qoder/rules/java-testing.md 存在,包含框架选择、命名规范、Mock 策略、覆盖要求、禁止项
  • 所有规则使用"必须 / 禁止"祈使句
  • 关键规则有正反示例
  • AGENTS.md 的快速导航表中已注册 4 个 Rules 文件
  • 每条规则可追溯到 Step 1 的架构文档

6. 与下一步的衔接

本步建立了 Rules 层硬性约束,锁定了技术栈和代码规范。下一步需要编写 Wiki 层(编码规范与参考资料)------Rules 层的"详细展开版",提供更丰富的上下文知识。

复制代码
Step 2(本步)                    Step 3(下一步)
┌─────────────────┐              ┌─────────────────────┐
│ always-on.md    │   约束展开    │ conventions/         │ ← 编码规范详细版
│ agent-workflow  │ ──────────▶  │   naming.md          │ ← 命名细则
│ java-code-style │   规则细化    │   error-handling.md  │ ← 错误处理细则
│ java-testing    │              │   logging.md         │ ← 日志细则
└─────────────────┘              │ reference/           │ ← 参考资料库
                                 │   prd-template.md    │ ← PRD 输入模板
                                 │ design/_template.md  │ ← 设计文档模板
                                 └─────────────────────┘

衔接关系

  • java-code-style.md 的命名规则 → conventions/naming.md 的详细命名表
  • java-testing.md 的测试规则 → conventions/testing.md 的详细测试实践
  • always-on.md 的日志规范 → conventions/logging.md 的日志格式细则
  • agent-workflow.md 的设计文档要求 → design/_template.md 的设计文档模板
  • agent-workflow.md 的 PRD 输入 → reference/prd-template.md 的 PRD 模板

说明

  • 实际示例的格式是markdown格式,在示例中出现\符号是因为格式采用markdown编辑的,若不转译就会直接markdown格式断裂。使用时将\去掉即可