diff --git a/AGENTS.md b/AGENTS.md index d01e685..f838657 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -47,14 +47,48 @@ - 改了界面上用户能看出来的东西; - 你不确定它算不算小改动。 -Gitea 使用约定(**首次使用前需由项目负责人补全**): +### 0.1 Gitea 使用约定 -- Gitea 地址:`<待填写>` -- 仓库:`<待填写>` -- 工单标签:`<待填写>` -- 里程碑命名:`<待填写>` +- **地址:** +- **仓库:** `chengma/cmautobuy` +- **工单层级靠标题前缀区分**,不使用标签和里程碑(当前两者均未启用, + 也不要去建——`AGENTS.md` §1 已说明阶段用章节和清单表达,不加正式层级): -在补全之前,按 §3.6 处理:输出完整工单草稿并说明阻塞,不要跳过建单直接实施。 + | 前缀 | 含义 | + |---|---| + | `[Epic]` | 大工单 | + | `[MVP]` | MVP 工单 | + | 无前缀 | 单元任务 | + +- **跨子项目:** Admin 的工单标题加 `Admin:` 前缀;Client 的不加前缀。 + +### 0.2 没有工单不许改代码 + +`[必须]` **正式实施前必须有 Gitea 工单号。** 聊天里的工单草稿**不算工单**—— +它没有编号,提交引用不了,后续也追溯不到。 + +`[必须]` Gitea 连不上或信息缺失时,按 §3.6 输出完整草稿并说明阻塞, +然后**每次都明确询问用户是否授权本次直通**。 + +- **不得默认直通。** +- **不得因为上一次直通过,就默认这次也可以。** + +### 0.3 防呆:看到工单链接就说明 Gitea 可用 + +`[必须]` **只要在任何地方看到本仓库的 Gitea 工单链接**——用户消息、提交信息、 +`docs/task` 归档、代码注释——就说明 Gitea 是通的。此时必须: + +1. 立刻回填 §0.1 缺失的信息(地址和仓库名从工单 URL 里就能拿到); +2. **停止使用直通路径**,改回正常的建单流程。 + +**这条是有代价换来的。** 曾经发生过:用户已经给出 +`http://ilaer.eicp.net:8418/chengma/cmautobuy/issues/12`, +地址和仓库名就在 URL 里,但助手没识别出那就是自己一直在要的信息, +继续拿"Gitea 未配置"当理由跳过建单,还在提交信息里写下 +"Gitea 尚未配置,本次无对应工单号"——而同一个提交的标题里就引用着 `(#12)`。 + +`[必须]` 提交信息里**不得出现"Gitea 未配置 / 无工单号"这类说法**, +除非你在同一次回复里已经明确向用户说明阻塞并得到了直通授权。 ### 1. 工单层级与职责 diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..35049a6 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,210 @@ +# 多模型协作规则 + +本文件只讲**谁做什么、怎么交接、怎么审查**。 + +项目本身的规则(红线、工单流程、技术栈、分层、安全)全部在 +[AGENTS.md](AGENTS.md) 和各子项目的 `AGENTS.md` 里,**本文件不重复、不复述**—— +复述一次就走样一次,两份文档迟早说不一样的话。 + +--- + +## 1. 为什么这样分工 + +不按"任务难不难"分,按**错了多久才会被发现**分: + +| 错误类型 | 什么时候暴露 | 代价 | +|---|---|---| +| 设计决策错 | 几周后,可能是买错货才发现 | 数据已经脏了,返工 + 真金白银 | +| 代码实现错 | 跑测试的那一刻 | 改掉重跑,几分钟 | +| 复述文档错 | 人一看就发现 | 重问一次 | + +所以:**设计交给最强的模型,实现交给能靠测试兜住的,只读查询交给最便宜的。** + +## 2. 角色分工 + +| 角色 | 模型 | 干什么 | 交付物 | +|---|---|---|---| +| **架构** | Opus | 分析需求和缺陷、定根因、设计方案、写工单、**审查实现** | 工单(模板 A) | +| **实现** | Sonnet | 按工单写代码和测试、跑验证、改对应文档 | 代码 + 测试 + 实际验证输出 | +| **查询** | Haiku | 查文档回答问题、汇总现状、检查链接、找规则出处 | 带出处的答复 | + +--- + +## 3. 架构(Opus) + +### 必须做 + +- 动手前**读代码和数据**确认事实,不要基于猜测设计。 + 本项目有过教训:靠猜写进文档的"新设备第一次 claim 必然返回 204"是错的。 +- 方案里每条**看起来多余的约束,必须写清它在防什么**(见 §4)。 +- 设计完**自己实跑一次关键路径**再宣布可用。本项目两个并发缺陷 + (PRAGMA 没作用到连接池、事务 `BEGIN DEFERRED` 死锁)都是 + 单线程读代码看不出来、跑起来才炸的。 +- 发现自己之前说错了,直接改正并说明,不要顺着圆。 + +### 不得做 + +- 不得在没有工单的情况下让下游改代码。 +- 不得把"我认为对"当成"已验证"。没跑过就说没跑过。 + +--- + +## 4. 交接物:工单必须自足 + +**下游拿到工单时没有你的上下文。** 它会把理由不明的约束当成冗余优化掉。 + +所以每条硬性约束都要带一句"为什么": + +```text +✗ sku_mappings 主键用 (shopee_sku_id, pdd_goods_id) + +✓ sku_mappings 主键用 (shopee_sku_id, pdd_goods_id) + —— 只用 shopee_sku_id 的话,PDD 商品从 A 换成 B 后旧映射还在, + B 恰好有同名规格时会静默买错东西,而且事后查不出来 +``` + +工单必须包含 [模板 A](docs/templates/task.md) 的 6 项,**一项都不能省**: + +1. 基本信息 +2. 要解决什么(缺陷附复现步骤) +3. **做什么 / 不做什么** ——「不做」和「做」一样重要,防止范围蔓延 +4. 已确认的方案,含预计修改文件,**每条约束带理由** +5. 可逐项打勾的验收标准 +6. 可直接复制的验证命令 + +--- + +## 5. 实现(Sonnet) + +### 必须做 + +- 动手前读根 `AGENTS.md` 的红线和对应子项目的 `AGENTS.md`。 +- **严格按工单的「不做」清单**,不顺手做别的。范围蔓延会让工单没法独立验收和回退。 +- 每写完一部分就编译 / 跑测试,不要攒到最后。 +- 完成后跑完整验证并**贴出实际输出**,不要只说"通过了"。 +- 报告里必须写明三件事: + 1. 哪些验收项**没做到**; + 2. 你**偏离工单**的任何决定及原因; + 3. **未验证到的部分**(没有就写"无",不许留空)。 + +### 不得做 + +- **不得改工单范围。** 觉得方案有问题就停下来退回架构角色,不要自作主张改设计。 +- **不得删改看不懂的约束或测试。** 测试红了先想"是不是我改错了", + 而不是"这个测试过时了"。本项目的测试名就是规则本身 + (例如 `TestSubmitResult_任务已取消仍然接受`),删掉它等于删掉一条业务规则。 +- **不得用目录级 `git add`。** 逐个文件暂存,避免把别人正在改的东西卷进提交。 +- 不得提交 git,除非工单明确要求。 + +--- + +## 6. 查询(Haiku) + +### 必须做 + +- **引用原文并给出处**(文件 + 章节号),不要转述规则。规则被转述一次就走样一次。 +- 查不到就说查不到,不要推测。 + +### 不得做 + +- **不得判断设计是否合理**,那是架构角色的事。 +- **不得修改任何文件**,包括文档。 +- 不得回答"应该怎么做",只回答"文档里怎么写的"。 + +--- + +## 7. 审查与返工 + +**实现交付 ≠ 完成。** 架构角色必须逐条审查,不达标就打回让实现继续做。 + +### 7.1 审查五步 + +按顺序做,**不许跳步**: + +| # | 检查 | 怎么做 | +|---|---|---| +| 1 | **自己跑验证** | 亲自执行工单里的验证命令,**不采信报告里的结论**。读代码看不出并发问题,跑一次就知道 | +| 2 | **验收标准逐条对照** | 一条条核,不许"整体看起来没问题"。没做到的要能指出是哪一条 | +| 3 | **看 diff 有没有削弱约束** | 有没有删测试、放宽 `CHECK`、去掉校验、把 `[必须]` 改成 `[建议]`。**这类改动一律先当成错的**,除非工单明确要求 | +| 4 | **看范围有没有蔓延** | 有没有做「不做」清单里的事,有没有顺手改无关文件 | +| 5 | **追问"未验证到的部分"** | 写"无"的时候要**格外怀疑**。真实的任务几乎总有没验证到的东西(真机行为、迁移、并发、边界) | + +### 7.2 打回时必须说清三件事 + +打回不能只说"不行",否则实现只能靠猜: + +1. **哪一条**验收标准没达到(引原文); +2. **当前是什么**(贴实际输出或代码片段); +3. **期望是什么**(可验证的描述,不是"改好一点")。 + +```text +✗ 测试不够,再补一些 + +✓ 验收标准「换回 A 后 A 的映射仍然可用」没有对应测试。 + 当前 sku_mappings 相关只有 3 个用例,都是单一 PDD 商品的场景。 + 需要新增:匹配 A → 换到 B → 换回 A → 断言 A 的映射直接可用、 + 不需要重新匹配。 +``` + +### 7.3 不要替它改 + +审查发现问题,**打回让实现去改,不要自己动手改完说"我帮你修了"**。 + +原因有两个:架构角色的时间应该花在设计和审查上;以及实现角色下次还会犯同样的错。 + +例外:**只有一处、且是纯笔误**(拼错、格式)时可以直接改,并在报告里说明。 + +### 7.4 打回两次还不对,问题在工单 + +**同一个点被打回两次仍未达标,就不要再打第三次。** 这基本可以确定是 +工单没写清楚,不是实现能力问题。这时架构角色要做的是: + +1. 重读自己写的那条要求,**找出哪里有歧义**; +2. 改工单,把约束和理由写具体(往往是缺了"为什么"); +3. 或者判断这块确实需要完整上下文,**自己接手做**。 + +继续打回只会来回消耗。 + +### 7.5 实现暴露了设计问题,架构要认 + +实现过程中经常会暴露设计缺陷——这是好事,说明问题在便宜的阶段被发现了。 + +`[必须]` 这时**改工单,不要让实现硬凑**。本项目就发生过:并发测试报 +`SQLITE_BUSY`,根因是 `db.go` 里 PRAGMA 的用法错了,不是测试写得不对。 +当时如果让实现"想办法让测试过去",很可能会去改测试而不是改根因。 + +### 7.6 通过的标准 + +同时满足才算完成: + +- [ ] 架构角色**亲自跑过**验证命令,输出符合预期 +- [ ] 验收标准逐条达成,未达成的已明确记录并有后续安排 +- [ ] diff 里没有未经工单批准的约束削弱 +- [ ] 没有范围蔓延 +- [ ] "未验证到的部分"如实列出 + +--- + +## 8. 绝对不下放的事 + +碰到下面任何一条,**必须由架构角色处理,不得交给实现或查询角色**: + +1. 根 `AGENTS.md` 的**五条红线**相关的任何改动 +2. **金额、幂等、崩溃恢复、并发**相关的设计 +3. **数据库结构变更的设计**(实现可以下放,设计不行) +4. **接口契约变更**(两个子项目之间的边界) +5. 任何**"错了要几周后才发现"**的判断 + +判断不了算不算,就当作算。 + +--- + +## 9. 验证是唯一的验收依据 + +- 说"通过了"必须附**实际命令输出**。 +- 说"实现了"必须有**能跑的测试**。 +- 说"验证过"必须**真的跑过**,不是读代码推断的。 +- 没跑到的部分**必须明说**,不允许留空。 + +本项目已经证明:单线程读代码看不出并发问题,测试跑一次就抓到了—— +而且抓到了两次,两次根因还不一样。