diff --git a/.cursor/skills/clarify/SKILL.md b/.cursor/skills/clarify/SKILL.md new file mode 100644 index 00000000..c1e5c2df --- /dev/null +++ b/.cursor/skills/clarify/SKILL.md @@ -0,0 +1,286 @@ +--- +name: clarify +description: | + AI 产品经理 skill,帮助用户将模糊想法澄清为清晰的需求卡片。 + 触发场景:用户有一个想法或功能需求但表达不清晰,需要理清思路再让 AI 编码实现。 + 工作流:启动时定位当前 SOP 任务目录下的 01-clarify.md,阶段一引导发现真实需求,阶段二苏格拉底式挑战假设,最终将需求卡片写入 .specs/plans/<任务目录>/01-clarify.md(不生成 PRD、AI coding prompt 等独立产物)。 + 不适用:需求已经足够明确、只需要直接技术实现的场景。 +--- + +你是一个有丰富经验的产品经理,有强烈的用户同理心和犀利的产品直觉。你不是表单向导——你倾听、感受、大胆猜测,然后和用户一起把想法逼清楚。 + +**你的姿态**:在阶段一,你是一个有温度的朋友,先感同身受,再大胆猜测用户真正想要什么。在阶段二,你切换成苏格拉底——友善但毫不留情地挑战每一个假设。 + +**铁律:每轮只处理一件事。不批量问问题,不一次性抛出多个质疑。** + +--- + +## 启动流程 + +clarify 启动时,**先定位当前 SOP 任务目录的 `01-clarify.md`,再进入澄清流程**。 + +> ⚠️ **重要**:本项目使用 `.specs/plans/YYYY-MM-DD_/` 的 SOP 任务目录体系。 +> ⚠️ **重要**:本项目使用 `.specs/plans/YYYY-MM-DD_/` 的 SOP 任务目录体系。 +> clarify 的最终产物**必须且只能**写入该任务目录下的 `01-clarify.md`。 +> **禁止**新建 `prd/` 目录、**禁止**创建 `YYYYMMDD-HHMM-*.md` 格式的独立需求文件、**禁止**覆盖用户项目里的其他文件。 + +### 第一步:定位当前任务的 `01-clarify.md` + +1. 运行 `git branch --show-current` 获取当前分支名。 +2. 在 `.specs/plans/` 下查找与当前分支匹配的任务目录:遍历各 `.specs/plans/*/00-overview.md`,匹配 Meta 中 `分支` 字段等于当前分支名的那个目录即为当前任务。 +3. 目标文件路径固定为:`.specs/plans/<任务目录>/01-clarify.md` + +> ⚠️ 本项目**不维护**全局 `.specs/plan.md`——任务发现完全依赖 `plans/` 目录 + 各自的 `00-overview.md`。 + +若出现以下情况,**不要**自行新建任务目录,而是**提示用户**按 `CODEBUDDY.md` 的「SOP 启动前置:分支与任务判断」流程先建立任务目录(含填好 `00-overview.md` 的 Meta `分支` 字段),再重新启动 clarify: +- 当前在 `master` 或其他非 `feature/` 分支 +- `feature/xxx` 分支在任何 `00-overview.md` 的 Meta 中都找不到匹配 +- 找不到对应任务目录 + +### 第二步:检查 `01-clarify.md` 现状 + +读取目标 `01-clarify.md` 文件,判断其状态并决定迭代策略: + +- **文件不存在 / 只是模板占位(空白或全是 TODO 标记)** + → **新建模式**:进入 Discovery 阶段,完成后输出需求卡片到 `01-clarify.md`(覆盖写入) + +- **文件已有有效澄清内容** + → 询问用户: + > 当前任务已有 Clarify 文档,这次是要: + > 1. **完全重写**:Discovery + Challenge 后覆盖重写整个 `01-clarify.md` + > 2. **局部补充**:基于现有内容进行局部澄清,追加到 `01-clarify.md` 的「补充澄清」章节末尾 + > 3. **只读参考**:仅把现有内容作为上下文,我只是想讨论,暂不修改文件 + + - 选项 1 → Discovery + Challenge → **覆盖写入** `01-clarify.md` + - 选项 2 → Discovery + Challenge → **追加写入** `01-clarify.md` 末尾新增的「## 补充澄清 - YYYY-MM-DD」章节 + - 选项 3 → 完成澄清对话,**不写文件**,只在对话中输出 + +--- + +## 工作模式 + +用户说出初始想法后,**自动进入 clarify 流程**,无需额外指令。 + +- **标准模式**(默认):阶段一 Discovery → 阶段二 Challenge → 输出文档 +- **快速模式**:用户说"快速模式"或"跳过质疑"时,只走阶段一 → 直接输出文档 + +--- + +## 阶段一:Discovery(需求发现) + +**目标**:帮用户说清楚自己真正想要什么。 + +**核心模式**:共情认同 → 大胆猜测 → 追问验证 + +### 每轮交互结构 + +1. **先共情**(1 句):认同用户感受或处境,让用户感到被理解 + - "听起来这个问题已经让你花了不少冤枉路……" + - "这种感觉很常见——脑子里清楚,但就是说不出来……" + +2. **再猜测**(1-2 句):大胆推断用户真实意图,主动说出来 + - "我猜你真正想要的不只是 XXX,而是……" + - 宁可猜错被纠正,不要模糊保守 + - 聚焦用户痛点和使用场景,不是技术实现 + +3. **最后追问**(最多 1 个问题):针对当前最不确定的维度 + +**STOP:等待用户回应后再继续下一轮。不连续追问。** + +### 追问维度(按优先级) + +1. 这是为谁解决什么问题?(目标用户 + 痛点) +2. 用户完成这件事的核心路径是什么?(主流程) +3. 哪些事是明确不做的?(边界) +4. 成功的标准是什么? + +### 规则 + +- **情感优先**:第一句永远是共情,不是分析 +- 语气像有经验的朋友,不是顾问或机器 +- 每轮只推进一个维度,不轰炸问题 +- AI 自判断清晰度:目标用户、核心场景、关键约束都明确后,主动宣布准备进入阶段二 +- 宣布时询问用户:"需求基本清晰了,我们进入挑战阶段?还是直接出文档?" + +### 开场示例 + +> 听起来你已经被这个问题困扰了挺久——需求说不清楚,做到一半又要改,很消耗人。我猜你真正想要的不只是一个文档模板,而是一个能把脑子里那团模糊的东西"逼"出来的过程。是这个感觉吗? + +--- + +## 阶段二:Challenge(需求质疑) + +**目标**:挑战核心假设,确保需求经得起推敲。 + +**核心模式**:宣告氛围切换 → 逐一戳假设 → 灵魂拷问 + +### 进入时宣告氛围切换 + +> 好,需求我已经基本理解了。接下来我要换一个角色——会问一些可能让你不舒服的问题,但这正是为了帮你把想法变得更坚实。准备好了吗? + +### 每轮交互结构 + +1. **戳假设**:直接指出需求里最脆弱的一个前提 + - "我注意到你的整个方案依赖一个假设:……" + +2. **灵魂拷问**:用一个无法回避的问题逼用户正视 + - "如果这个前提不成立,你的设计还剩下什么?" + - "有没有更简单的方式能达到同样目的?" + - "你的目标用户真的有这个痛点,还是你在替他们假设?" + +3. **等待回应**: + - 用户动摇某假设 → "这块值得重新想想,我们回到阶段一把这一块重新梳理一下?" + - 用户坚持且有理由 → 继续下一个质疑点 + - 用户想提前结束 → 接受并进入输出阶段 + +**STOP:每次只质疑一个假设,等待回应后再继续。** + +### 质疑角度 + +- 这个问题真的需要这个解法吗?有没有更简单的替代? +- 目标用户真的有这个痛点,还是我们在猜? +- MVP 是否过重?哪些功能可以先砍掉? +- 有没有没考虑到的边界情况或异常流程? +- 这个功能和已有工具的核心差异是什么? + +### 规则 + +- 阶段二**不共情**,直接、犀利 +- 语气是"我在帮你",不是"我在否定你" +- 挑战完所有核心假设(通常 3-5 个)后,主动进入输出阶段 + +### 质疑示例 + +> 我注意到你的整个方案都建立在"用户愿意多轮对话"这个假设上。但现实是——大多数人打开一个工具,三句话内没有价值感就会直接关掉。如果用户在第二轮就不耐烦了,你的 skill 还剩下什么? + +--- + +## 输出阶段 + +需求确认后,输出**单一**产物——**需求卡片**(一屏内)。**不**生成 PRD、AI coding prompt 等其它文件。 + +### 需求卡片 + +``` +# [项目名] + +**一句话目标**:[用一句话说清楚这个产品/功能是什么] +**核心用户**:[谁在用,在什么场景下用] +**做什么**: +- [核心功能 1] +- [核心功能 2] +- [核心功能 3] +**不做什么**:[明确排除的功能或场景] +**成功标准**:[用户用完后,什么状态算成功] +``` + +> 背景 / 目标 / 风险点等更结构化的拆解,统一在 `01-clarify.md` 的对应章节(参考 plans 模板的「§1 背景 / §2 目标 / §3 风险点」)补充;clarify 对话本身的产物只需这一张卡片。 + +### 保存需求文件 + +输出需求卡片后,将完整内容写入当前 SOP 任务目录的 `01-clarify.md`: + +1. **保存路径**:启动时定位到的 `.specs/plans/<任务目录>/01-clarify.md`(**唯一目标**,禁止新建其他需求文件) +2. **写入策略**(按启动时用户选择的模式): + - **新建模式** / **完全重写** → **覆盖写入** `01-clarify.md` + - **局部补充** → 在原文件末尾**追加**一个新章节 `## 补充澄清 - YYYY-MM-DD`,其下放置本次需求卡片 + - **只读参考** → **不写文件**,仅在对话中输出 +3. **禁止行为**: + - ❌ 不得新建 `prd/` 目录 + - ❌ 不得创建 `YYYYMMDD-HHMM-[需求名].md` 或 `-patch.md` 格式的独立文件 + - ❌ 不得生成 `PRD.md` / `AI-Coding-Prompt.md` 等独立产物 + - ❌ 不得修改 `00-overview.md` 以外的 SOP 产物文件 +4. **保存完成后告知用户**:`已保存至 .specs/plans/<任务目录>/01-clarify.md` + +`01-clarify.md` 文件内容结构(新建 / 覆盖时): + +```markdown +--- +created: YYYY-MM-DD +updated: YYYY-MM-DD +--- + +# [项目名 / 需求标题] + +## 需求卡片 + +**一句话目标**: +**核心用户**: +**做什么**: +- +**不做什么**: +**成功标准**: +``` + +局部补充时,在原文件末尾追加: + +```markdown + +--- + +## 补充澄清 - YYYY-MM-DD + +### 需求卡片 + +**一句话目标**: +**核心用户**: +**做什么**: +- +**不做什么**: +**成功标准**: +``` + +输出并保存完成后,用以下格式做总结确认,并**主动提醒用户回到 SOP 主流程**: + +``` +════════════════════════════════════════ +需求澄清完成 +════════════════════════════════════════ +核心用户:[xxx] +核心问题:[xxx] +Discovery 轮数:[N 轮] +Challenge 挑战数:[N 个假设] +输出:需求卡片 ✓ +已保存:.specs/plans/<任务目录>/01-clarify.md + +👉 下一步:请回到 SOP 主流程,确认是否结束 Clarify 步骤并进入 Plan 步骤。 +════════════════════════════════════════ +``` + +--- + +## 状态机 + +``` +启动 + ↓ +定位当前 SOP 任务目录(基于 git 分支 + 遍历 .specs/plans/*/00-overview.md 的 Meta `分支` 字段) + ↓ + ├── 未找到任务目录 → 提示用户先按 SOP 建立任务目录,终止流程 + └── 找到 .specs/plans/<任务目录>/01-clarify.md + ↓ +检查 01-clarify.md 现状 + ├── 不存在 / 模板占位 → 新建模式(覆盖写入) + └── 已有有效内容 → 询问:完全重写 / 局部补充 / 只读参考 + ├── 完全重写 → 覆盖写入 + ├── 局部补充 → 追加「## 补充澄清 - YYYY-MM-DD」章节 + └── 只读参考 → 不写文件 + ↓ +用户说出想法 + ↓ +阶段一 Discovery(多轮,每轮:共情 → 猜测 → 追问) + ↓ +AI 判断清晰度足够 → 询问:进入质疑 or 快速出文档? + ↓ +┌── 快速模式 ──────────────────────────────→ 输出 → 按写入策略落盘 +│ +└── 标准模式 + ↓ + 阶段二 Challenge(逐一挑战核心假设,通常 3-5 个) + ↓ + 用户动摇 → 回阶段一(局部重梳理)→ 再次进入阶段二 + ↓ + 用户确认 / 提前退出 + ↓ + 输出 → 按写入策略落盘到 01-clarify.md → 完成总结 → 提醒回到 SOP 主流程 +``` diff --git a/.specs/docs/apis/_template.md b/.specs/docs/apis/_template.md new file mode 100644 index 00000000..cdc32b08 --- /dev/null +++ b/.specs/docs/apis/_template.md @@ -0,0 +1,59 @@ +# + +> 复制为 `apis//.md` 并按实填充。 +> Source: <被测代码路径> +> Last-verified: + +--- + +## 描述 + + + +## 请求 + +**方法 / 路径**:`POST /v1/` 或 `Action=` + +### 入参 + +| 字段 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------| +| | | | | | + +### 示例 + +```json +{ + "Action": "" +} +``` + +## 响应 + +### 出参 + +| 字段 | 类型 | 说明 | +|------|------|------| +| | | | + +### 示例 + +```json +{ + "Response": { + "RequestId": "xxx" + } +} +``` + +## 错误码 + +| Code | 含义 | 处理建议 | +|------|------|---------| +| | | | + +## 变更记录 + +| 日期 | 版本 | 变更内容 | 任务 | +|------|------|---------|------| +| | | | | diff --git a/.specs/docs/apis/index.md b/.specs/docs/apis/index.md new file mode 100644 index 00000000..d95a0a4e --- /dev/null +++ b/.specs/docs/apis/index.md @@ -0,0 +1,32 @@ +# 接口文档总索引 + +> 每个对外接口对应一个 `/.md`。 +> 新增 / 修改接口时同步更新本索引。 + +--- + +## 命名约定 + +- 路径:`docs/apis//.md` +- 文件名 = 接口名(PascalCase 或项目既有风格) +- 每篇至少包含:描述、入参、出参、错误码、示例、变更记录 + +--- + +## 模块清单 + + + +| 模块 | 路径 | 接口数 | +|------|------|-------| +| | `apis//` | | + +--- + +## 接口清单 + + + +| 接口 | 模块 | 文档 | +|------|------|------| +| | | | diff --git a/.specs/docs/devops/env.md b/.specs/docs/devops/env.md new file mode 100644 index 00000000..8fa07b5b --- /dev/null +++ b/.specs/docs/devops/env.md @@ -0,0 +1,63 @@ +# 环境搭建与启动 + +> 让新人在 30 分钟内本地跑起来;产物与 CI / 部署完全一致。 +> 与 `test-env-deploy.md`(测试环境部署)、本目录其它运维文档配套。 + +> Source: <信息源:Makefile / package.json / pyproject.toml / Dockerfile / CI 配置> +> Last-verified: + +--- + +## 一、运行环境 + +| 环境 | 解释器 / 运行时 | 依赖目录 | 构建工具 | 部署场景 | +|------|----------------|---------|---------|---------| +| | | | | | + +> 例:开发机用 Python 3.x、容器用 venv、CI 用 Docker 镜像等。 + +--- + +## 二、快速启动 + +### 本地开发 + +```bash +# TODO: 项目实际启动方式 +# 1) 安装依赖 +# 2) 准备配置 / .env +# 3) 启动 / 进入 REPL +``` + +### 本地调试 + +```bash +# TODO: 调试模式启动命令(含 console log / 单步调试入口等) +``` + +--- + +## 三、配置体系 + +### 3.1 配置文件结构 + +``` +etc/ +├── common. # 全局公共配置 +├── . # 多地域配置 +└── .ini # 运行时参数 +``` + +### 3.2 关键配置项 + +| 配置路径 | 说明 | +|---------|------| +| | | + +--- + +## 四、常见问题 + +| 现象 | 原因 | 解决 | +|------|------|------| +| | | | diff --git a/.specs/docs/devops/test-env-deploy.md b/.specs/docs/devops/test-env-deploy.md new file mode 100644 index 00000000..4cb7ad71 --- /dev/null +++ b/.specs/docs/devops/test-env-deploy.md @@ -0,0 +1,113 @@ +# 测试环境部署与代码同步 + +> 本文档说明测试环境相关操作的 Skill 调用方式。 +> 所有环境操作通过 **`cvm-dev-workflow` Skill** 统一处理,无需手动执行 CLI 命令。 +> +> 本文档由 `specs-sop` skill 维护;初始化或升级 skill 时**会强制刷新**(旧文件自动备份为 `test-env-deploy.md.bk.`)。 +> 项目特有的「组件清单」「环境命名」等定制内容请填到下文 `## 项目自定义` 章节,避免被刷新覆盖。 + +--- + +## Skill 纵览 + +| Skill | 用途 | 触发方式 | +|-------|------|---------| +| `cvm-dev-workflow` | 环境创建 / 查询、代码热更、远端命令执行 | 对 AI 说"创建环境"、"同步代码"、"查看日志"等 | +| `cvm-test-tools` | 创建/查询/销毁实例、数据库查询、API 调用 | 对 AI 说"创建实例"、"数据库查询"、"执行接口测试"等 | + +--- + +## 环境操作(cvm-dev-workflow) + +> 以下操作统一通过 `cvm-dev-workflow` Skill 完成,AI 会自动调用对应的环境管理能力。 + +| 操作 | 对 AI 说 | 说明 | +|------|---------|------| +| 创建测试环境 | `创建环境` / `创建环境 ` | 触发创建流水线,约 10–20 分钟 | +| 查询环境状态 | `查询环境 ` | 查看环境是否 READY | +| 查询流水线进度 | `查询流水线` | 查看创建/更新流水线状态 | +| 热更代码到环境 | `热更代码到 ` | 不走流水线,秒级生效 | +| 更新指定组件 | `更新组件 ` | 触发组件级重部署 | +| 远端容器执行命令 | `在 上执行 ` | 查日志、排查问题等 | +| **释放测试环境** | `释放环境 ` / `cvm-envx release -e ` | **SOP Commit 阶段的强制前置动作**;本任务收尾必须执行,由 `cvm-dev-workflow` 代为执行 `cvm-envx release -e `(同时完成环境池标记释放 + 平台 Session 释放)。详见 `plans/_template/09-commit.md` 第 0 节 | + +**环境状态说明** + +| 状态 | 含义 | +|------|------| +| `READY` | 就绪,可以同步代码 | +| `RUNNING` / `CREATING` | 创建/部署中,等待后重新查询 | +| `ERROR` / `FAILED` | 失败,查看流水线日志排查 | + +--- + +## 集成测试操作(cvm-test-tools) + +> 以下操作通过 `cvm-test-tools` Skill 完成。 + +| 操作 | 对 AI 说 | 说明 | +|------|---------|------| +| 创建测试实例 | `创建实例` | 创建用于 IT 的 CVM 实例 | +| 查询实例 | `查询实例 ` | 查看实例状态 | +| 销毁实例 | `销毁实例 ` | 清理测试实例 | +| 数据库查询 | `数据库查询 ` | 查询测试环境数据库 | +| 调用 CVMAPI | `cvmapi ` | 直接调用 CVM 接口 | +| 调用 VSAPI | `vsapi ` | 直接调用 VS 接口 | + +--- + +## 工具就绪检查 + +在使用上述 Skill 前,先确认 `cvm-envx` CLI 已安装(`cvm-dev-workflow` 依赖)。 + +### 检查 cvm-envx 是否就绪 + +```bash +cvm-envx --version +``` + +| 输出 | 状态 | 处理方式 | +|------|------|----------| +| 打印版本号(如 `x.y.z`) | ✅ 就绪 | 可直接使用 | +| `command not found` | ❌ 未安装 | 见下方安装引导 | + +### 安装 cvm-envx(通过 vortex) + +```bash +cd /tmp +git clone git@git.woa.com:cvm/vortex.git /tmp/vortex +bash /tmp/vortex/install_public.sh /tmp/vortex_space +``` + +安装脚本会自动完成:卸载旧版 `@tencent/zhiyan-cle-cli` → 安装 `@tencent/cvm-env-cli` → 执行 `cvm-envx init`。 + +安装完成后再次执行 `cvm-envx --version` 确认就绪。 + +### 工具检查清单 + +| 工具 | 检查命令 | 缺失处理 | +|------|---------|---------| +| `cvm-envx` | `cvm-envx --version` | 见上方安装引导 | +| `git` | `git --version` | 系统包管理器安装 | + +--- + +## 项目自定义 + +> 本章节内容**不会**被 skill 刷新覆盖,请按项目实际情况填充。 + +### 组件清单 + +| 组件名 | 仓库 / 路径 | 主分支 | 备注 | +|--------|------------|--------|------| +| | | | | + +### 常用环境 + +| 环境名 | 用途 | 负责人 | 备注 | +|--------|------|--------|------| +| | | | | + +### 项目特有同步规则 / 排雷点 + + diff --git a/.specs/docs/integration_test/integration_test.md b/.specs/docs/integration_test/integration_test.md new file mode 100644 index 00000000..0ff03817 --- /dev/null +++ b/.specs/docs/integration_test/integration_test.md @@ -0,0 +1,241 @@ +# 集成测试规范(环境 / 用例 / 运行调试) + +> 让任意成员(或 AI Agent)能在**真实或近真实环境**把集成测试**搭起来、写得对、跑得通、出错查得到**。 +> 三段式结构:① 环境与依赖 / ② 用例设计与组织 / ③ 运行与调试。 +> +> **与单元测试的边界**: +> - 单元测试(`.specs/docs/unittest/unittest.md`):函数 / 模块级,**禁止**真实外部调用,全部 Mock。 +> - 集成测试(本文):跨模块 / 跨服务 / 跨进程链路,**允许**调用真实测试环境的依赖(DB / MQ / 上下游服务 / 第三方 SDK 测试桩)。 +> +> **若仓库存在项目集成测试规则文件**(`.codebuddy/rules/integration_test_*.md`、`.cursor/rules/`、`.windsurf/rules/` 等或同义命名如 `it_rule.md`、`api_test_rule.md`,见 `CODEBUDDY.md` 文末「项目既有规则」),那是权威来源:本文以摘录 + 链接形式承接,不另起冲突;调整本文必须同步 rules。 + +> Source: <信息源:tests/it 或 integration/ 目录 + CI 集成测试 job + 项目规则文件(integration_test_*.md 等)+ 测试环境部署文档> +> Last-verified: + +--- + +## 一、环境与依赖 + +### 1. 集成测试形态判定 + +> 不同项目的"集成测试"含义不同,先明确本项目落在哪一种(可多选),再决定如何搭环境。 + +| 形态 | 典型场景 | 依赖准备方式 | +|------|---------|-------------| +| **接口级 IT**(API 黑盒)| 调用 HTTP/RPC 接口验证业务流程 | 需要可用的测试环境地址 + 鉴权 | +| **链路级 IT**(多服务联动)| 验证 A→B→C 的端到端链路 | 全链路测试环境 + 数据隔离方案 | +| **数据库 IT** | 验证 DAO / migration / 事务行为 | 独立测试库(容器或共享库 + 隔离 schema) | +| **消息 / 异步 IT** | 验证 MQ 消费 / 定时任务 / 回调 | 独立 topic / queue + 消费组隔离 | +| **前端 IT**(E2E) | 验证页面交互、跨页流程 | Playwright / Cypress + 后端 mock 或测试环境 | + +> 在下方填写**本项目实际形态**,并标注权重(哪些为主、哪些为辅): +> +> + +### 2. 测试环境信息 + +> **强依赖** `.specs/docs/devops/test-env-deploy.md`:环境的"如何创建/部署/同步"在 devops 文档中,本节只记录"集成测试需要的环境形态与连通信息"。 + +| 项 | 说明 | 示例 / 实际值 | +|----|------|--------------| +| 环境名称 / 类型 | 持久共享环境 还是 临时按需环境 | <填> | +| 接入地址 | 入口域名 / IP / 端口 | <填> | +| 鉴权方式 | Token / 证书 / IAM / 临时 AKSK | <填> | +| 数据隔离策略 | 独立账号 / 独立 schema / 独立 namespace / tag 隔离 | <填> | +| 清理策略 | 自动清理(TTL / 标签删除)/ 手动清理 / 不清理 | <填> | +| 上下游依赖 | 见 `.specs/docs/relationship.md`,列出 IT 必须可达的依赖 | <填> | + +### 3. 前置依赖检查清单(先查再装) + +> 任何一项已满足就跳过对应安装步骤,不要无脑重置环境。 + +```bash +# (1) 测试环境可达性 +<填:curl -sS --max-time 5 /healthz && echo "env OK" || echo "env unreachable"> + +# (2) 鉴权凭证就绪(不打印明文) +<填:test -n "$_IT_TOKEN" && echo "token OK" || echo "缺少 token"> + +# (3) 集成测试客户端依赖(与单元测试隔离的 venv 或独立工具) +<填:venv/bin/python -c "import " 2>/dev/null && echo "deps OK" || echo "缺依赖"> + +# (4) 测试数据 fixture / 种子数据 +<填:test -f tests/it/fixtures/.sql && echo "fixture OK" || echo "需要导入 fixture"> + +# (5) 隔离资源(独立 topic / namespace 等) +<填:项目特有检查命令> +``` + +判断逻辑:5 项全过 → 直接执行 IT;某项失败 → **只修复失败项**,不要全量重建。 + +### 4. 环境变量与配置 + +| 变量 | 用途 | 示例 | +|------|------|------| +| <例:`_IT_ENDPOINT`> | 测试环境入口地址 | `https://test-api.example.com` | +| <例:`_IT_TOKEN`> | 鉴权 token(**严禁硬编码**) | 从 vault / 环境变量注入 | +| <例:`_IT_NAMESPACE`> | 资源隔离命名空间 | `it--` | +| <例:`IT_DRY_RUN`> | 仅打印请求不真实下发 | `1` / `0` | + +> 集成测试环境变量**必须从 vault / CI secret / 本地 `.env.local`(已 gitignore)注入**,禁止写入仓库。 + +--- + +## 二、用例设计与组织 + +### 1. 通用强制条款(红线) + +| # | 红线 | +|---|------| +| 1 | **禁止**指向生产环境 / 共享线上库;只跑测试或 staging 环境 | +| 2 | **禁止**在 IT 中使用真实用户的真实凭证;用专用测试账号 | +| 3 | **禁止**测试遗留脏数据:每个用例自带 setup / teardown,或全局清理钩子保证幂等 | +| 4 | **禁止**用例间共享可变状态 / 依赖执行顺序(除非显式声明 `@order` 并文档化) | +| 5 | **禁止**硬编码环境信息(域名 / 路径 / 凭证 / 资源 ID) | +| 6 | **必须**记录 `req_id` / `trace_id` 到日志或报告,便于事后追溯 | +| 7 | **必须**为可能产生费用 / 不可逆操作的用例加保护开关(`IT_DRY_RUN` / 显式 confirm) | + +### 2. 用例类型与适用场景 + +| 类型 | 适用 | 文件命名 / 位置 | 示例风格 | +|------|------|----------------|---------| +| 接口正向用例 | 验证主流程 happy path | `tests/it//test__normal.py` | <填> | +| 接口逆向用例 | 参数错误 / 鉴权失败 / 资源不存在 | `tests/it//test__negative.py` | <填> | +| 端到端链路用例 | 跨服务 / 跨模块流程 | `tests/it/scenarios/test_.py` | <填> | +| 数据一致性用例 | DB / 缓存 / 副本数据校验 | `tests/it/data/test_.py` | <填> | +| 异步 / 时序用例 | MQ 消费 / 回调 / 定时任务 | `tests/it/async/test_.py` | <填> | + +### 3. 文件命名硬约束 + +- 集成测试文件**与单元测试目录隔离**(如 `tests/it/`、`tests/integration/`、`it/`),不要与 UT 混放 +- 每个被测接口 / 场景**独立文件**,命名直观体现"测什么 + 正向/逆向" +- 跨模块的端到端用例放到 `scenarios/` 子目录,避免归属歧义 +- BDD 项目:`.feature` 与 step 实现严格成对,feature 名包含场景关键词 + +### 4. 用例设计自检清单(四维度) + +> 每个用例必须明确以下四个维度的设定,避免"测了个寂寞"。 + +| 维度 | 检查点 | +|------|-------| +| **输入** | 必填 / 选填 / 边界值 / 非法输入是否覆盖 | +| **状态** | 前置状态准备(DB 行 / 资源已创建 / 上游已 mock)是否清晰 | +| **依赖** | 上下游依赖(见 `relationship.md`)哪些需要真实、哪些可桩 | +| **断言** | 不仅断言响应码,还要断言核心字段、副作用(DB 写入 / 消息发送 / 日志输出) | + +### 5. Mock / 桩策略 + +> 集成测试默认**真实调用**,但仍有需要桩的场景,避免连不上 / 不可控的依赖把 IT 变红。 + +| 类别 | 默认策略 | +|------|---------| +| 本项目核心接口 | **真实调用** | +| 同测试环境内的下游服务 | **真实调用** | +| 跨域 / 第三方 SDK(短信 / 支付 / 邮件) | 接入第三方提供的 sandbox / 测试模式;无 sandbox 时使用本地桩 | +| 不可控外部(如运营商 / 真实物理设备) | 必须桩;用例标注 `@requires_real` 显式排除 | +| 时间 / 随机 | 谨慎使用;如必要,用专用 fixture 隔离 | + +### 6. 与项目 rules 承接 + +- 若仓库存在项目集成测试规则文件(`.codebuddy/rules/integration_test_*.md`、`.cursor/rules/` 等或 `it_*.md`):本文 §二 改为指向该 rules 锚点,不重复写 +- 否则使用本文规范作为最低基线 +- 与 `.specs/plans/_template/06-it.md`(IT 阶段产物模板)配套使用:本文写"规则",06-it.md 写"本次任务的执行结果" + +--- + +## 三、运行与调试 + +### 1. 标准执行命令 + +```bash +# 全量集成测试(CI 主入口) +<填:sh run_it.sh / make it / pytest tests/it -m it / npm run test:e2e> + +# 指定模块 / 文件 +<填:sh run_it.sh tests/it/> + +# 指定单个用例 +<填:sh run_it.sh -k ""> + +# Dry-run(不真实下发,仅校验拼接的请求) +<填:IT_DRY_RUN=1 sh run_it.sh ...> + +# 仅重跑失败用例 +<填:sh run_it.sh --lf> + +# 带 trace / 详细日志 +<填:sh run_it.sh -vv --log-cli-level=INFO> +``` + +> **必须**与 CI 中跑的命令一致;本地能过、CI 失败的多半是环境变量 / 网络访问 / 权限差异。 + +### 2. 测试 runner 通常做了什么(如有 wrapper 脚本) + +> 例:`run_it.sh` 通常负责: +> 1. 检查测试环境可达性(healthz / readiness) +> 2. 注入测试 token / endpoint 环境变量 +> 3. 创建本次运行的隔离命名空间(`it-`) +> 4. 调用 runner 执行用例 +> 5. 失败时自动收集:失败用例的 `req_id` 列表、关键日志片段、环境快照 +> 6. 结束时按隔离策略清理资源(即使失败也清理;保留产物到 artifacts/) + +### 3. 调试套路 + +| 现象 | 优先排查 | 排查命令 | +|------|---------|---------| +| 全量失败 | 环境可达性 / 鉴权 / 配置 | 走 § 一的 5 项检查清单 | +| 全量超时 | 网络 / DNS / 测试环境过载 | `curl -v /healthz`;查测试环境监控 | +| 偶发失败(flaky) | 异步时序 / 资源竞争 / 依赖抖动 | 多次 `--lf` 重跑;检查是否依赖固定时序 | +| 单接口失败 | 抓取 req_id 查上下游链路日志 | 见 § 4 故障定位流程 | +| 用例间互相影响 | 数据隔离失效 / 全局状态 | 检查 setup/teardown / 命名空间隔离 | +| 鉴权失败 | token 过期 / 权限不足 | 重新签发 token;核对账号权限 | + +### 4. 故障定位流程(接口级 IT 通用) + +``` +失败用例 → 取 req_id / trace_id + → 查本服务日志(按 req_id 过滤) + → 看上下游调用链(trace_id 串联) + → 定位故障点(本服务 / 下游 / 数据问题) + → 修复 / 跟进 owner + → 重跑该用例确认 +``` + +> 失败处理原则与 `_template/06-it.md` 一致:环境问题 → 修复后重跑;代码问题 → 回 03-implement;设计问题 → 回 02-plan。 + +### 5. 不要 / 慎用 + +| 项 | 原因 | +|----|------| +| 在 IT 中使用 `time.sleep` 等死等 | 改用 `wait_until(condition, timeout)` 显式轮询 | +| 共用同一份测试数据不清理 | 数据污染会让后续用例不可重复 | +| 用例依赖前一个用例创建的资源 | 用例必须独立;如需链路,用单一用例覆盖完整链路 | +| 关闭某些用例(`@skip` / `xfail`)以"让 CI 过" | 必须在 `06-it.md` 备注原因 + 跟踪修复 | +| 把 IT 和 UT 混到同一个 runner | 跑得慢、失败原因混杂、报告难读 | + +### 6. 测试产物 + +| 产物 | 路径 | 用途 | +|------|------|------| +| HTML 测试报告 | <填:`it_report.html`> | 浏览器查看 | +| JUnit XML | <填:`junit-it.xml`> | CI 摄取(流水线展示) | +| 失败用例 trace 包 | <填:`artifacts/failed//`> | 包含日志、req_id、环境快照 | +| 终端摘要 | stdout | 通过 / 失败 / 跳过统计 | + +### 7. CI 集成 + +- IT 在 CI 中**应与 UT 分离**为独立 stage / job:UT 快、阻塞 PR;IT 慢,可选阻塞或定时跑 +- IT 失败必须**强制阻塞合入主干**(feature 分支可放宽,但需评审豁免) +- IT 失败后 CI 必须自动归档:`req_id` 列表、关键日志、环境快照(保留 ≥ 7 天) +- 测试环境部署 / 同步流程见 `.specs/docs/devops/test-env-deploy.md` + +--- + +## 四、与 SOP 阶段的关系 + +| 阶段 | 引用本文的方式 | +|------|---------------| +| **02 Plan** | 设计 IT 用例清单时,按 § 二的"四维度自检"框架列用例;命名遵循 § 二规则 | +| **05 Deploy** | 部署完成后须确认 § 一 §2「测试环境信息」可达,才能进入 06 IT | +| **06 IT** | 按 § 三的标准命令执行;失败定位走 § 三 §4;产物按 § 三 §6 收集到 `06-it.md` | +| **07 Docs** | 若本次任务新增 / 修改了 IT 用例约定 / 环境配置,同步本文档 | diff --git a/.specs/docs/relationship.md b/.specs/docs/relationship.md new file mode 100644 index 00000000..d29c66de --- /dev/null +++ b/.specs/docs/relationship.md @@ -0,0 +1,73 @@ +# 上下游 / 集成关系 + +> 本项目与外部世界的关系:谁在用它、它依赖了谁、依赖坏掉会怎样。 +> 引入新外部依赖、调整调用拓扑、修改集成方式时同步更新。 + +> Source: <扫描到依赖关系的来源:依赖管理文件 / 配置 / adapter 目录等> +> Last-verified: + +--- + +## 上游(谁在用本项目) + +| 调用方 / 集成方 | 代码仓库 | 用途 | 协议 / 集成方式 | 关键入口 | 联系人 | +|-----------------|---------|------|-----------------|---------|-------| +| | | | | | | + +> 集成方式示例:HTTP / RPC / 包依赖(npm / pypi / cargo / maven)/ CLI 嵌入 / SDK 引入 / WebHook 订阅 / 消息消费 +> **代码仓库**:填写完整 git 地址或仓库短名(如 `git.woa.com/cvm/xxx`、`github.com/org/repo`);内部组件请补完整路径,便于跨仓库跳转。 + +--- + +## 下游(本项目用了谁) + +| 被调方 / 被依赖方 | 代码仓库 | 用途 | 协议 / 集成方式 | 关键入口 | SLA / 版本约束 | 失败处理(超时 / 重试 / 降级)| 集成代码位置 | +|-------------------|---------|------|-----------------|---------|---------------|------------------------------|--------------| +| | | | | | | | | + +--- + +## 调用关系说明 + +> 对每一条**关键调用链**做功能性描述,避免只看表格不知道"为什么调"。 +> 推荐按 **业务场景 / 功能模块** 维度组织,每条说明包含:触发场景、调用方→被调方、传输的数据、失败影响。 + +### 1. <调用链名称,例:用户下单 → 订单服务 → 库存服务> + +- **触发场景**:<什么用户操作 / 定时任务 / 事件触发了这条链路> +- **调用拓扑**:`<上游组件>` ─→ `<本项目模块>` ─→ `<下游组件>` +- **传输数据**:<关键字段或消息体摘要,敏感字段标注脱敏> +- **关键代码**:`<本项目内的入口文件 / 函数路径>` +- **失败影响**:<这条链路断了会导致什么业务后果> +- **相关文档**:<对应 `apis//.md` 或下游仓库文档链接> + +### 2. <下一条调用链> + +- **触发场景**: +- **调用拓扑**: +- **传输数据**: +- **关键代码**: +- **失败影响**: +- **相关文档**: + +--- + +## 拓扑图 + + + +``` +[外部调用方] + ↓ +[本项目] ─→ [下游 A] + ├──────→ [下游 B] + └──────→ [存储 / 队列 / 第三方 API] +``` + +--- + +## 故障传播矩阵 + +| 下游 / 外部条件 | 受影响功能 | 失败表现 | 是否可降级 | 降级 / 兜底方案 | +|----------------|-----------|---------|-----------|----------------| +| | | | | | diff --git a/.specs/docs/sqls/README.md b/.specs/docs/sqls/README.md new file mode 100644 index 00000000..a9514a57 --- /dev/null +++ b/.specs/docs/sqls/README.md @@ -0,0 +1,29 @@ +# 数据库 / 持久化结构 + +> 集中存放数据库表结构 / Schema 定义文件,作为开发与 review 的权威依据。 +> DDL 变更必须同步更新此处。 + +--- + +## 目录约定 + +``` +sqls/ +├── README.md # 本文件 +└── /.sql # 或 _FINAL_SCHEMA.md(按项目实际) +``` + +## 维护原则 + +- DDL 与线上一致;改表必须同步本目录 +- 索引必记,新增查询条件前确认索引覆盖 +- 字段必带 COMMENT,枚举字段列出全部可能值 +- 任务模板 `02-plan.md` / `07-docs.md` 中已强制要求 DB 变更同步本目录 + +--- + +## 数据库清单 + +| DB | 用途 | 主要表 | 文档路径 | +|----|------|-------|---------| +| | | | | diff --git a/.specs/docs/unittest/unittest.md b/.specs/docs/unittest/unittest.md new file mode 100644 index 00000000..05b05336 --- /dev/null +++ b/.specs/docs/unittest/unittest.md @@ -0,0 +1,224 @@ +# 单元测试规范(环境 / 生成 / 运行调试) + +> 让任意成员(或 AI Agent)能在本地把单元测试**装得起、写得对、跑得通、出错查得到**。 +> 三段式结构:① 环境搭建 / ② 生成规范 / ③ 运行调试。 +> +> **若仓库存在项目 unittest 规则文件**(`.codebuddy/rules/unittest_*.md`、`.cursor/rules/unittest_*.md`、`.windsurf/rules/` 等,见 `CODEBUDDY.md` 文末「项目既有规则」),那是权威来源:本文以摘录 + 链接形式承接,不另起冲突;调整本文必须同步 rules。 + +> Source: <信息源:tests/ 目录 + Makefile / package.json / pyproject.toml + CI 配置 + 项目规则文件(unittest_*.md 等)> +> Last-verified: + +--- + +## 一、环境搭建与依赖安装 + +### 0. 推荐技术选型 + +| 类别 | 推荐 | 备选 | +|------|------|------| +| 解释器 / 运行时管理 | **pyenv**(Python)/ nvm(Node)/ rustup / sdkman | asdf | +| 虚拟环境隔离 | **venv**(Python 标准库自带)| poetry / pipenv / conda | +| 测试框架 | <填项目实际:pytest / pytest-bdd / unittest / vitest / jest / go test / cargo test …> | — | +| Mock / Stub | <填:unittest.mock / pytest-mock / sinon / mockito …> | — | +| 覆盖率 | <填:coverage.py + pytest-cov / c8 / nyc / go cover …> | — | + +> **为什么 pyenv + venv(Python 项目)**: +> - `pyenv` 解决"项目所需 Python 版本与系统 Python 不一致";可同机多版本共存 +> - `venv` 是 Python 自带虚拟环境,零额外依赖、与 IDE 兼容性最好、产物路径稳定(默认 `./venv/`) +> - 二者组合 = 「精确锁定 Python 版本」+「依赖隔离在仓库目录内」 + +### 1. 前置依赖检查清单(先查再装) + +> 任何一项已满足就跳过对应安装步骤,不要无脑 `rm -rf venv` 重建。 + +```bash +# (1) 解释器版本管理器 +command -v pyenv >/dev/null && echo "pyenv OK" || echo "需要安装 pyenv" + +# (2) 项目所需的解释器版本 +pyenv versions | grep -E "^[ *] *" >/dev/null && echo "Python OK" || echo "需要安装" + +# (3) 虚拟环境 +test -x venv/bin/python && venv/bin/python --version | grep -F "" \ + && echo "venv OK" || echo "venv 缺失或版本不对" + +# (4) 关键依赖 +venv/bin/python -c "import , , " 2>/dev/null \ + && echo "deps OK" || echo "缺少依赖" + +# (5) 项目特有产物(locale / proto 编译 / native 模块等,按需) +test -f <产物路径> && echo "extra OK" || echo "需要构建" +``` + +判断逻辑:5 项全过 → 直接执行测试;某项失败 → **只修复失败项**,不要全量重建(除非解释器版本不对)。 + +### 2. 分步安装(仅在上面检查失败时执行) + +#### Step 1: 安装 pyenv + +```bash +# macOS +brew install pyenv + +# Linux +curl https://pyenv.run | bash + +# 写入 shell 配置(仅首次) +export PYENV_ROOT="$HOME/.pyenv" +export PATH="$PYENV_ROOT/bin:$PATH" +eval "$(pyenv init -)" +``` + +#### Step 2: 安装项目所需 Python 版本 + +```bash +PY_VERSION="" # ← 与项目根 .python-version / pyproject.toml 一致 +pyenv install $PY_VERSION --skip-existing +pyenv local $PY_VERSION # 在仓库根写入 .python-version +``` + +#### Step 3: 创建 venv 并安装依赖 + +```bash +python3 -m venv venv +venv/bin/python -m pip install -U pip setuptools wheel +venv/bin/python -m pip install -r requirements.txt +# 或:venv/bin/python -m pip install -e ".[dev,test]" +``` + +#### Step 4: 编译 / 准备运行期产物(按项目实际) + +> 例:i18n locale、protobuf 生成文件、native 扩展、测试 fixture 数据下载等。 + +#### Step 5: 一键脚本(如有) + +> 项目通常会提供 `make test-setup` / `bash scripts/setup_test.sh` 等。**优先用一键脚本**,本节是其语义说明。 + +### 3. 环境变量与配置 + +| 变量 | 用途 | 示例 | +|------|------|------| +| <例:`_ETC_PATH`> | 加载测试专用配置目录 | `_ETC_PATH=./tests/conf` | +| <例:`PYTHONPATH`> | 注入项目根 / 模块路径 | `PYTHONPATH=.` | +| <例:``> | 强制启用本地 mock,禁止真实外部调用 | `=1` | + +> 测试相关环境变量必须**在测试 runner 内部设置**(如 `pytest.ini` / `conftest.py` / `Makefile` target),避免成员手动 export。 + +--- + +## 二、单元测试生成规范 + +### 1. 通用强制条款(红线) + +| # | 红线 | +|---|------| +| 1 | 不修改被测业务代码以让测试通过 | +| 2 | 不调用真实外部服务 / 真实写库 | +| 3 | 不在测试间共享可变状态 / 不依赖执行顺序 | +| 4 | 不删除已有测试代码,只追加 | +| 5 | 新 Mock / step / fixture 只能追加到对应文件**尾部** | +| 6 | 不硬编码环境信息(域名 / 路径 / 凭证) | + +### 2. 测试类型与适用场景 + +| 测试类型 | 适用 | 文件命名 / 位置 | 风格 | +|---------|------|----------------|------| +| 函数级单元测试 | 单个 / 少量函数小改 | `tests//test_.py` 或 `_test.py` | <填> | +| 大文件批量函数测试 | 同一文件多函数需测 | 同上,按类组织 | <填> | +| 接口 / 入口级测试 | 端到端入口 entry 流程 | `tests//_test.py` + `.feature`(BDD 时)| <填> | + +### 3. 文件命名硬约束 + +- 测试文件名**与被测代码文件 1:1 对应**(不附加函数名后缀) +- 同一被测文件的多个函数 / 多个场景测试**统一放进同一个 `<被测文件>_test.py`**;新增 → 追加,不新建并列文件 +- BDD 项目:`.feature` 与 `_test.py` 文件名严格成对 + +### 4. Mock 策略 + +| 类别 | 默认策略 | +|------|---------| +| 项目内函数 | 默认允许真实调用(utils / 校验器 / 纯函数)| +| 外部依赖(DB / HTTP / MQ / 文件系统 / 第三方 SDK)| 必须 Mock | +| 可观测性(日志 / 监控 / 指标上报)| 不 Mock | +| 时间 / 随机 | 用 `freezegun` / `monkeypatch` 显式控制 | +| 全局常量 | 用 `monkeypatch` / `try-finally` 自动恢复 | + +### 5. 用例设计自检清单 + +> 详见 `plans/_template/04-ut.md` § 用例设计清单(输入 / 状态 / 依赖 / 幂等四维度全覆盖)。 + +### 6. 与项目 rules 承接 + +- 若仓库存在项目 unittest 规则文件(`.codebuddy/rules/unittest_*.md`、`.cursor/rules/` 等):本文 §二 改为指向该 rules 锚点,不重复写 +- 否则使用本文规范作为最低基线 + +--- + +## 三、运行与调试规范 + +### 1. 标准执行命令 + +```bash +# 全量 +<填:sh run_test.sh / make test / npm test / go test ./... / cargo test> + +# 指定文件 / 目录 +<填:sh run_test.sh tests//_test.py> + +# 关键字匹配 +<填:sh run_test.sh -k ""> + +# 仅重跑失败用例 +<填:sh run_test.sh --lf> + +# 带覆盖率 +<填:sh run_test.sh --cov=> + +# 按标记 / tag +<填:sh run_test.sh -m > +``` + +> **必须**与 CI 中跑的命令一致;本地能过、CI 失败的多半是环境变量 / 路径差异。 + +### 2. 测试 runner 通常做了什么(如有 wrapper 脚本) + +> 例:`run_test.sh` 通常负责: +> 1. 设置必要环境变量(`_ETC_PATH` 等) +> 2. 清理上次运行残留(`__pycache__` / `.pytest_cache` 等) +> 3. patch 已知第三方库 bug(幂等) +> 4. 调用 `venv/bin/ "$@"`,把命令行参数透传 + +### 3. 调试套路 + +| 现象 | 优先排查 | 排查命令 | +|------|---------|---------| +| 全量失败 | 环境 / 依赖 / locale / 配置 | 走 § 一的 5 项检查清单 | +| 单文件失败 | 隔离复现 | ` tests//file -vvs` | +| 偶发失败 | 顺序污染 / 全局状态 | ` --lf` + 检查 fixture scope | +| 覆盖率不达标 | 看未覆盖行 | `coverage report -m` / 看 HTML 报告 | +| import 报错 | venv 损坏 / 路径错 | `venv/bin/python -c "import "` | +| Mock 没生效 | patch 路径错 | "在哪 import 就 patch 哪"(`module.<被 import 名>`)| + +### 4. 不要 / 慎用 + +| 项 | 原因 | +|----|------| +| 修改 `conftest.py` / `pytest.ini` / `run_test.sh` 等共享配置 | 影响全员,需走 PR 评审 | +| 启用并行(如 `-n auto`)| 多数旧测试架构不支持 xdist 并行,会引入偶发失败 | +| 在测试中 `print` 大量调试信息 | 改用 `-vvs` + `caplog` | +| 关闭某些用例(`@skip`)以"让 CI 过"| 必须在 04-ut.md 备注原因 + 跟踪修复 | + +### 5. 测试产物 + +| 产物 | 路径 | 用途 | +|------|------|------| +| HTML 测试报告 | `<填:unittest_report.html / report.html>` | 浏览器查看 | +| 覆盖率 XML | `<填:coverage.xml>` | CI / SonarQube 摄取 | +| 覆盖率 HTML | `<填:htmlcov/>` | 本地交互式查看 | +| 终端摘要 | stdout | 通过 / 失败 / 未覆盖行 | + +### 6. CI 集成 + +- CI 中跑测试必须**与本地命令一致**(仅可加 `--junitxml` / `--cov-report` 等输出参数) +- 失败必须阻塞合入 +- 覆盖率回退(如低于 baseline N%)应触发警告或阻塞,由项目自定阈值 diff --git a/.specs/plans/_template/00-overview.md b/.specs/plans/_template/00-overview.md new file mode 100644 index 00000000..0f0f7280 --- /dev/null +++ b/.specs/plans/_template/00-overview.md @@ -0,0 +1,158 @@ +# [YYYY-MM-DD] <任务标题> + +` 标记的注释块 + 4. 整段删除每块(含标记行),替换为下面这段单行指针(出现 N 次就替换 N 次): + + + + 5. 头部"⚠️ TEMPLATE ONLY"那段**也整段删除**(只存在于 _template/) + +**为什么精简**: + - 任务文件噪音:~30 行规则在每个任务里都重复,10 个任务 = 10 份副本 + - 版本漂移:规则改了只有 _template/ 通过 init_specs.sh 同步,旧任务副本不同步 + - 单一真相源:SOP 规则只在 _template/ 维护,AI 查规则时只看 _template/ +═══════════════════════════════════════════════════════════════════════════ +--> + +> **本文件是本任务的单一真相源(Single Source of Truth)**:任务元信息、进度、当前步骤、关键决策全部在这里。 +> 会话恢复时,先读本文件定位当前步骤,再按需加载对应阶段文件。 +> +> ⚠️ 本项目**不维护**全局 `.specs/plan.md`——跨任务查看请列 `.specs/plans/` 目录。 +> ⚠️ Meta 中的 `分支` 字段是上下文恢复时定位任务的唯一依据,**必须**与 `git branch --show-current` 的输出完全一致。 + +--- + +## Meta + +| 项 | 值 | +|----|----| +| 分支 | `feature/xxx` | +| Issue / TAPD | `--story=xxx` / `#123` | +| 摘要 | 一句话描述 | +| 状态 | 🟡 待开始 / 🔵 进行中 / ✅ 已完成 / ❌ 已取消 | +| 创建日期 | YYYY-MM-DD | +| 负责人 | | +| 预期完成 | YYYY-MM-DD | +| 开发模式 | 独立开发 / 协同开发(design.md 驱动) | +| 测试环境 | (协同开发时填写 design.md 中指定的环境名) | +| 预估代码改动行数 | (Plan 阶段填入;不含测试 / 文档) | +| 小需求模式 | ⬜ 否 / ✅ 是(`预估代码改动行数 ≤ 10` 时勾选) | +| 模型 | | + +--- + +## Progress + + + + + +- [ ] 01. Clarify → [01-clarify.md](./01-clarify.md) +- [ ] 02. Plan → [02-plan.md](./02-plan.md) +- [ ] 03. Implement → [03-implement.md](./03-implement.md) +- [ ] 04. UT → [04-ut.md](./04-ut.md) +- [ ] 05. Docs → [05-docs.md](./05-docs.md) +- [ ] 06. Review → [06-review.md](./06-review.md) +- [ ] 07. Commit → [07-commit.md](./07-commit.md) + +--- + +## 当前步骤 + +> 恢复会话时,优先读取此处指向的阶段文件。 + +- **步骤**:⏳ 01. Clarify +- **文件**:[01-clarify.md](./01-clarify.md) +- **上次更新**:YYYY-MM-DD HH:MM:SS + +--- + +## 时间记录 + + + + + +| # | 步骤 | 开始时间 | 结束时间 | 耗时 | 对话轮次 | 备注 | +|---|------|---------|---------|------|---------|------| +| 01 | Clarify | | | | | | +| 02 | Plan | | | | | | +| 03 | Implement | | | | | | +| 04 | UT | | | | | | +| 05 | Docs | | | | | | +| 06 | Review | | | | | | +| 07 | Commit | | | | | | + +--- + +## 关键决策备忘 + +> **跨阶段共享的关键上下文**。仅记录影响后续步骤的决策,避免恢复时还要翻阅历史阶段文件。 +> 填写建议:接口命名最终选型、DataType 字段设计、兼容性约束、与其它模块的约定、跳过的步骤及原因等。 + +- + +--- + +## 风险速览 + +> 任务级风险登记。高严重风险可按需在 `.specs/docs/` 下单独归档,避免跨任务共享文件造成合并冲突。 + +| # | 风险 | 严重度 | 缓解 | +|---|------|-------|------| +| | | | | + +--- + +## 文件索引 + +| 文件 | 产物 | +|------|------| +| [00-overview.md](./00-overview.md) | 任务总览(本文件) | +| [01-clarify.md](./01-clarify.md) | 需求澄清:背景、目标、范围、待确认问题 | +| [02-plan.md](./02-plan.md) | 方案设计:改动文件、调用链、数据模型、IT 用例 | +| [03-implement.md](./03-implement.md) | 实现:关键细节、与 Plan 差异、检查结果 | +| [04-ut.md](./04-ut.md) | 单元测试:用例、覆盖率、未覆盖行 | +| [05-docs.md](./05-docs.md) | 文档更新清单 | +| [06-review.md](./06-review.md) | Code Review:问题与修复 | +| [07-commit.md](./07-commit.md) | Commit message 与 amend 流程 | diff --git a/.specs/plans/_template/01-clarify.md b/.specs/plans/_template/01-clarify.md new file mode 100644 index 00000000..eebd17ba --- /dev/null +++ b/.specs/plans/_template/01-clarify.md @@ -0,0 +1,69 @@ +# 01. Clarify + +> **目的**:把模糊想法澄清为可执行需求。本阶段聚焦 **背景 / 目标 / 风险点** 三件事,务必与用户充分对齐。 +> **推荐辅助**:使用 `skill: clarify` 澄清需求;AI 切换为「产品经理」角色完成 Discovery + Challenge 双阶段对话。若 skill 不可用,按下方「决策框架」手工推进。 +> **输入**:用户原始描述 / TAPD 单 / Issue 链接 +> **输出**:本文件填写完整 + `00-overview.md` 关键决策备忘登记要点 + +--- + +## 1. 背景 (Context) + +> 为什么要做?业务 / 技术痛点是什么?不做会怎样? + + + +## 2. 目标 (Goal) + +> 做到什么程度算完成?量化指标优先。 + +**主要目标**: +- + +**成功指标(可验证)**: +| 指标 | 当前值 | 目标值 | 验证方式 | +|------|-------|-------|---------| +| | | | | + +## 3. 风险点 + +> **需求层面**的高层风险(业务 / 合规 / 资源依赖 / 跨团队协作等),每条必须给出缓解或兜底。技术实现风险(接口 / 数据 / 兼容等)留到 `02-plan.md §8` 风险与兜底详写。 + +| # | 风险 | 严重度 | 缓解 / 兜底 | +|---|------|-------|------------| +| | | 🟡 中 | | + +## 4. 待确认问题 (Open Questions) + +> 每个问题必须有结论才能进入下一步。**禁止**带着未决问题进入 Plan 阶段。 + +| # | 问题 | 结论 | 决策人 | +|---|------|------|-------| +| 1 | | | | + +## 5. 关联 (References) + +- TAPD / Issue: +- 相关接口 / 设计文档 / ADR: +- 上游 / 下游依赖: + +--- + +## 决策框架 + +1. **5W1H 自检**:Why / What / Who / Where / When / How 每项能否一句话回答? +2. **INVEST**:需求是否满足 Independent、Negotiable、Valuable、Estimable、Small、Testable? + +## 反例 + +❌ **目标含糊** → "`DescribeInstances` P99 从 800ms 降到 200ms,通过 benchmark 脚本在 dev 环境 5000 QPS 下验证。" +❌ **风险点无缓解** → 写明"风险 + 严重度 + 缓解/兜底",避免"已知有风险,但暂未想到方案"。 + +## 完成标志 + +- [ ] 背景与目标已写明,目标可量化 +- [ ] 风险点已识别并给出缓解/兜底 +- [ ] 所有 Open Questions 均已有明确结论 +- [ ] 关键决策已同步到 `00-overview.md` 的「关键决策备忘」 +- [ ] `00-overview.md` Progress / 当前步骤 / 时间记录已同步 +- [ ] 已与用户完成结束确认:"Clarify 已完成,是否进入 Plan?" diff --git a/.specs/plans/_template/02-plan.md b/.specs/plans/_template/02-plan.md new file mode 100644 index 00000000..559ddd88 --- /dev/null +++ b/.specs/plans/_template/02-plan.md @@ -0,0 +1,161 @@ +# 02. Plan + +> **目的**:把 Clarify 的结论转化为可落地的技术方案。 +> **输入**:`01-clarify.md` 的目标与范围 +> **输出**:改动清单、调用链、数据模型、**UT 用例(TDD 先行)**、IT 用例 +> **TDD 模式**:本阶段必须**先于 Implement** 设计完 UT 用例(§ 6);UT/IT 边界与红绿循环约束详见 `04-ut.md` §0.5,本文件只列 UT 用例骨架,重复内容不复制。 + +--- + +## 1. 方案概述 + +> 一段话描述整体方案,含关键抉择。 + +## 2. 改动文件清单 + +| 文件 | 改动类型 | 说明 | +|------|---------|------| +| | 新增 / 修改 / 删除 | | + +> **原则**:每行对应一个文件,不要把多个文件合并。新增文件要写明所在目录。 + +## 3. 影响范围 + +| 维度 | 影响 | +|------|------| +| 接口 | | +| 模块 | | +| DB schema | | +| 配置 | | +| 协议兼容 | | +| 上下游服务 | | + +## 4. 调用链 + +``` +<入口接口> + → <层 1> + → <层 2> + → <最终存储 / 外部调用> +``` + +> 标出**新增**或**修改**的节点,与原链路的差异用注释说明。 + +## 5. 数据结构变更 + +### 5.1 内部 DataType / Schema + +| 类型 | 字段 | 类型 | 必填 | 说明 | +|------|------|------|------|------| +| | | | | | + +### 5.2 DB 表结构 + +| 表 | 变更 | 索引影响 | 回滚方式 | +|----|------|---------|---------| +| | | | | + +> 持久化结构变更必须同步修改 `.specs/docs/sqls/` 对应文件(DB schema / migration / 协议帧 / 配置 schema 等)。 + +### 5.3 协议 / 接口契约 + +| 接口 | 新增字段 | 必填 | 兼容性 | +|------|---------|------|-------| +| | | | | + +> **兼容性检查**:新增字段是否可选?旧客户端是否仍能正常工作? + +## 6. UT 用例设计(TDD 必填,先于 Implement) + +> **硬要求**:本节必须先于 Step 3 落地;Implement 阶段按 Red → Green → Refactor 推进,**禁止**"先写代码再补 UT"。 +> 设计目标:每个核心函数 / 关键分支至少一个 UT;UT 全 Mock 验证函数级,IT 走真实链路验证调用链,**两者不重复测同一层**(详见 `04-ut.md` §0.5)。 + +### 测试类型说明 + +| 类型 | 测试范围 | 依赖处理 | 适用场景 | +|------|---------|---------|---------| +| **函数级 UT** | 单个函数 / 类方法 | 全Mock(含项目内跨模块调用) | 核心算法、校验逻辑、工具函数 | +| **场景 UT** | 完整业务调用链(入口 → 多层 → 外部边界) | Mock 外部边界(DB / MQ / RPC / HTTP),项目内真实调用 | IT 场景无法在 CI 自动跑时;功能覆盖率补充 | +| **IT**(§7) | 真实链路端到端 | 真实环境 | 冒烟验证、上下游联调 | + +> **场景 UT 说明**:Mock 范围仅限项目外部依赖(DB / MQ / Redis / 第三方 API),项目内各层正常调用。有IT 覆盖的场景**不强制**再写场景 UT;但若IT依赖特定测试环境而无法在 CI 自动跑,则**推荐**补充对应场景 UT 以保证 CI 功能覆盖率。 + +### 6.1 函数级 UT 用例 + +| # | 被测对象(函数 / 类 / 模块路径) | 测试文件(计划) | 类型 | 输入 | 期望输出 / 行为 | Mock 边界 | +|---|----------------------------------|------------------|------|------|----------------|-----------| +| 1 | `business..` | | 正向 | | | DB / 外部 API | +| 2 | | | 逆向(非法输入) | | 抛 `` | | +| 3 | | | 边界(最大/最小/空) | | | | +| 4 | | | 异常(依赖故障) | | | mock 抛 `Timeout` | +| 5 | | | 幂等(重复调用) | | 状态/副作用一致 | | + +> **硬要求**:至少覆盖 **正向 + 逆向 + 边界** 三类;写操作必加**幂等类**;调用外部依赖的函数必加**异常类**。 +> 「Mock 边界」必须显式声明本用例 Mock 了哪些依赖,避免 UT 退化成隐式 IT。 + +### 6.2 场景 UT 用例(可选,IT 无法在 CI 自动跑时填写) + +| # | 业务场景 | 入口(函数 / 接口) | 测试文件(计划) | 类型 | 关键断言 | Mock 边界(仅外部) | +|---|---------|-------------------|------------------|------|---------|-------------------| +| 1 | | | | 正向 | | DB / MQ / RPC | +| 2 | | | | 逆向| | | +| 3 | | | | 异常(外部故障) | | mock 外部抛错 | + +> **硬要求**:「Mock 边界」只写外部依赖,项目内层级**不 Mock**;禁止把场景 UT 写成函数级 UT 的堆砌。 +> Implement 阶段若发现 UT 设计缺口,**必须回到本节补充**并重新进入 Red → Green,禁止"先把代码写完再补 UT"。 + +## 7. IT 用例设计 + +| # | 场景 | 类型 | 前置条件 | 执行步骤 | 预期结果 | +|---|------|------|---------|---------|---------| +| 1 | | 正向 | | | | +| 2 | | 正向(典型) | | | | +| 3 | | 逆向(非法输入) | | | | +| 4 | | 边界(上限 / 下限) | | | | +| 5 | | 异常(依赖故障) | | | | +| 6 | | 幂等 | | | | + +> **硬要求**:至少覆盖 正向 + 逆向 + 边界 三类;涉及外部调用须加 异常类;写操作须加 幂等类。 + +## 8. 风险与兜底 + +| 风险 | 触发条件 | 影响 | 缓解 | 回滚方案 | +|------|---------|------|------|---------| +| | | | | | + +## 9. 工时估算 + +| 阶段 | 工时 | 备注 | +|------|------|------| +| Implement | | 含 TDD 写测试时间 | +| UT | | 含红绿循环 + 覆盖率达标 | +| Deploy + IT | | | +| Docs + Review | | | +| **预估代码改动行数** | **<行数>** | **不含测试 / 文档;≤ 10 时把 `00-overview.md` Meta `小需求模式` 设为 ✅** | + +--- + +## 决策框架 + +1. **先画图**:调用链、数据流、状态机,能画成图的不要用文字。 +2. **找相似**:先看项目内有没有类似接口 / 模块,复用已有模式优于新造。 +3. **最小改动**:能改一个文件解决,就不要改两个。 +4. **边界优先**:先列出所有边界 / 异常场景,再想正向路径。 + +## 反例 + +❌ **改动清单过粗** → 逐文件列出(`business/auth/login.py` 新增手机号分支、`framework/validator.py` 新增 `PhoneNumber` 类型),不要"改造 auth 模块"。 +❌ **IT 用例只有正向** → 至少 正向 / 逆向 / 边界 三类;写操作加幂等,外部依赖加异常。 +❌ **DB 变更无回滚** → 写明"加字段 `last_login_ip VARCHAR(45) NULL`,回滚通过 `ALTER TABLE DROP COLUMN`"。 + +## 完成标志 + +- [ ] 改动文件清单完整,每文件有说明 +- [ ] 调用链清晰(推荐配图) +- [ ] 数据结构变更含回滚方式 +- [ ] **函数级 UT 用例已设计**(§6.1),覆盖正向 / 逆向 / 边界,写操作含幂等,外部依赖含异常;Mock 边界已显式声明 +- [ ] **场景 UT 用例已评估**(§6.2),IT 无法在 CI 自动跑的场景已补充场景 UT;Mock 边界仅限外部依赖 +- [ ] IT 用例覆盖 正向 / 逆向 / 边界,必要时加异常与幂等 +- [ ] 风险表有缓解与回滚 +- [ ] `00-overview.md` Progress / 当前步骤 / 时间记录已同步 +- [ ] 已与用户完成结束确认 diff --git a/.specs/plans/_template/03-implement.md b/.specs/plans/_template/03-implement.md new file mode 100644 index 00000000..9aa16a44 --- /dev/null +++ b/.specs/plans/_template/03-implement.md @@ -0,0 +1,40 @@ +# 03. Implement + +> **目的**:按 Plan 写代码,只记录改动点。 +> **输入**:`02-plan.md` +> **输出**:代码改动 + 本文件 + +--- + +## 1. 改动文件清单 + +| # | 文件 | 改动摘要 | +|---|------|---------| +| 1 | `path/to/file` | 一句话描述做了什么 | +| 2 | `path/to/file` | | + +## 2. 与 Plan 的差异 + +> 偏离 `02-plan.md` 时必须记录原因。 + +| # | 偏离项 | 原因 | +|---|--------|------| +| | | | + +## 3. 自检 + +- [ ] 无硬编码凭证 / Token / 密码 +- [ ] SQL 全部参数化 +- [ ] 外部输入均有校验 +- [ ] 错误路径有日志 +- [ ] Lint / Format 通过 + +--- + +## 完成标志 + +- [ ] 所有改动文件已实现 +- [ ] 与 Plan 偏离项已记录 +- [ ] 自检全部通过 +- [ ] `00-overview.md` Progress / 当前步骤 / 时间记录已同步 +- [ ] 已与用户完成结束确认 diff --git a/.specs/plans/_template/04-ut.md b/.specs/plans/_template/04-ut.md new file mode 100644 index 00000000..76deb8b1 --- /dev/null +++ b/.specs/plans/_template/04-ut.md @@ -0,0 +1,148 @@ +# 04. UT + +> **目的**:以单元测试证明行为正确、回归可防。 +> **输入**:`02-plan.md §6` UT 用例设计 + `03-implement.md` 完成的代码 +> **输出**:测试文件 + 覆盖率报告 + 本文件 +> **TDD 模式**:本阶段是 `02-plan.md §6.2` 红绿循环的"绿 + 重构"产物——所有 UT 用例**应来自** Plan §6 的设计表;Implement 阶段已先写过失败 UT(Red),本阶段确认全部转绿(Green)并完成必要的 Refactor。 + +--- + +## 0. 前置阅读(强制) + +进入本阶段前**必须**先读以下文件,确认环境 / 生成规范 / 运行命令;不要凭记忆写测试: + +1. **`02-plan.md` §6 UT 用例设计** — 本阶段的用例清单基线,§ 1 表必须**逐条对齐**这一节 +2. **`.specs/docs/unittest/unittest.md`** — 单元测试规范(环境搭建 / 生成规范 / 运行调试 三段式) +3. **项目规则文件中的 unittest 规则**(若仓库存在 `.codebuddy/rules/unittest_*.md`、`.cursor/rules/unittest_*.md` 等)— 项目专属硬规则(命名 / 禁止事项 / Mock 策略等),优先级高于 2 +4. **`.specs/docs/devops/env.md`** — 本地环境搭建(确认 venv / 依赖 / locale 等已就绪) + +> 若 2 / 3 不存在或与项目实际脱节 → 暂停 UT,先在 Stage 07 Docs 修订或新建对应文档,再回来执行 UT。 +> 若 1(Plan §6)缺失或仅有占位 → 不能进入本阶段,必须**回 Step 2 Plan** 补齐 UT 用例设计后再执行。 + +--- + +## 0.5 TDD 工作流自检 + +| 阶段 | 期望状态 | 当前情况 | +|------|---------|---------| +| 🔴 Red(Implement 前/中) | Plan §6 列出的 UT 已先写、首次跑全部失败 | ⬜ 已完成 / ⬜ 跳过(说明原因) | +| 🟢 Green(Implement 后) | 实现使所有 UT 转绿 | ⬜ 已完成 | +| 🔵 Refactor | 在 UT 保持绿的前提下重构代码 | ⬜ 已完成 / ⬜ 无需重构 | + +> 若 Red 阶段被跳过(例如 hotfix 紧急修复),必须在备注栏写明原因;常规需求不得跳过。 +> Refactor 阶段若发现 Plan 设计本身有问题(如 UT 难以编写说明耦合过强),回到 Step 2 Plan 调整方案,**禁止**通过弱化 UT 来回避问题。 + +--- + +## 1. 用例清单 + +> **必须与 `02-plan.md §6` UT 用例设计逐条对齐**——本表是 Plan 设计的执行落地。新增 / 删除 / 调整必须**先回写** Plan §6,再在此处更新。 + +| # | Plan §6 编号 | 用例名 | 测试文件 | 类型 | 状态 | +|---|-------------|--------|---------|------|------| +| 1 | §6-1 | | | 正向 | ⬜ | +| 2 | §6-2 | | | 逆向 | ⬜ | +| 3 | §6-3 | | | 边界 | ⬜ | +| 4 | §6-4 | | | 异常 | ⬜ | +| 5 | §6-5 | | | 幂等 | ⬜ | + +> 状态:⬜ 未执行 \| ✅ 通过 \| ❌ 失败 \| ⏭ 跳过(需备注原因) +> 若 Plan §6 编号列出现 `+`(如 `§6-3+`)表示本阶段在 Plan 之外补充的用例,**必须**在结束确认时把补充内容回写 Plan §6。 + +## 2. 执行命令 + +```bash +# TODO: 填入项目实际命令 +# 例: +# sh run_test.sh --cov=business.. +``` + +## 3. 结果 + +| 项 | 值 | +|----|----| +| 通过 / 总数 | / | +| 覆盖率 | % | +| 达标(≥ 80%) | ⬜ 是 / 否 | + +**未覆盖行**: +``` +<文件>:<行号> <说明为什么未覆盖> +``` + +## 4. 失败定位 + +| 用例 | 失败原因 | 修复动作 | 修复后状态 | +|------|---------|---------|-----------| +| | | | | + +--- + +## 用例设计清单(Checklist) + +为保证覆盖度,按下列清单对每个被测函数自检: + +### 输入维度 +- [ ] 空输入 / None / 空串 / 空列表 / 空 dict +- [ ] 单元素 / 多元素 +- [ ] 最小值 / 最大值 / 超限 +- [ ] 类型错误(期望 int 给了 str) +- [ ] 非法字符 / 注入类(SQL、路径穿越、脚本) +- [ ] Unicode / Emoji / 超长字符 + +### 状态维度 +- [ ] 资源不存在 +- [ ] 资源已存在 / 冲突 +- [ ] 资源状态与操作不匹配(如已终止的实例被关机) +- [ ] 并发竞态(可用 mock 时钟模拟) + +### 依赖维度 +- [ ] 依赖返回成功 +- [ ] 依赖返回业务错误 +- [ ] 依赖超时 +- [ ] 依赖抛异常 + +### 幂等 / 重试 +- [ ] 相同请求重复执行,结果一致 +- [ ] 部分成功后重试,不产生副作用 + +--- + +## 禁止事项(红线) + +- ❌ **改业务代码让测试过**。测试与代码分歧时,先判断哪边对;若代码错,开 bug 修复任务,**不要**在本任务里偷偷改。 +- ❌ **调用真实外部服务**。全部 mock。 +- ❌ **用例间依赖执行顺序**。任意顺序执行结果必须相同。 +- ❌ **硬编码环境信息**。用 fixture / 配置注入。 +- ❌ **新增 mock / step 插入文件中间**。只能追加到文件尾部。 + +--- + +## 反例 + +❌ **反例 1:只测 happy path** +> 测了 `login(user="alice", pwd="123456") == True`,没有测错误密码、锁定、空用户等。 + +❌ **反例 2:断言过弱** +> `assert result is not None` — 没法发现大部分 bug。 + +✅ **改写** +> `assert result.code == 0 and result.user_id == expected_id and result.session_token.startswith("sess_")` + +❌ **反例 3:Mock 返回值与真实不一致** +> Mock DB 查询返回 `{}`,但真实 DB 返回 `None`。 + +✅ **原则** +> Mock 以真实行为为准,可抓一次真实返回作为 fixture。 + +--- + +## 完成标志 + +- [ ] 所有用例通过 +- [ ] 覆盖率 ≥ 项目目标(通常 80%) +- [ ] 未覆盖行有说明 +- [ ] 无修改被测业务代码以绕过失败的行为 +- [ ] 新增 Mock / step 仅追加到文件尾部 +- [ ] 已在 `00-overview.md` Progress 勾选 04. +- [ ] 已与用户完成结束确认 diff --git a/.specs/plans/_template/05-docs.md b/.specs/plans/_template/05-docs.md new file mode 100644 index 00000000..71e03f36 --- /dev/null +++ b/.specs/plans/_template/05-docs.md @@ -0,0 +1,82 @@ +# 07. Docs + +> **目的**:保证代码改动对应的所有文档同步更新,防止"代码跑偏、文档留守"。 +> **输入**:代码改动 + Plan / Implement / IT 的产物 +> **输出**:更新后的文档文件 + +--- + +## 1. 必检清单 + +> 实际路径必须先从 `.specs/docs/` 目录中确认。不适用的项填"➖ 不涉及"。 + +**架构与上下游** +- [ ] `.specs/docs/architecture.md` — 系统架构(新增模块 / 改调用链 / 改并发模型时) +- [ ] `.specs/docs/relationship.md` — 上下游 / 集成方关系(新增依赖 / 调整拓扑时) + +**对外接口 / 契约** +- [ ] 接口文档 `.specs/docs/apis//.md`(新增 / 修改接口必改) +- [ ] 接口总索引 `.specs/docs/apis/index.md`(新增接口时追加) + +**数据 / 持久化** +- [ ] DB schema / migration `.specs/docs/sqls/<...>`(DDL 变更时必改) + +**测试规范** +- [ ] `.specs/docs/unittest/unittest.md`(测试约定 / 命名 / Mock 策略变更时) +- [ ] 若仓库存在 unittest 项目规则(`.codebuddy/rules/unittest_*.md` / `.cursor/rules/` 等),作为权威来源同步修订 + +**环境 / 部署** +- [ ] `.specs/docs/devops/env.md`(环境搭建 / 启动方式变化时) +- [ ] `.specs/docs/devops/test-env-deploy.md`(测试环境部署 / 同步流程变化时) + +**全局** +- [ ] 对外 README / 用户指南 — 对用户可见的变更 +- [ ] CHANGELOG — 版本变更日志 + +## 2. 改动明细 + +| 文档 | 路径 | 改动类型 | 改动说明 | 状态 | +|------|------|---------|---------|------| +| | | 新增 / 修改 | | ⬜ | + +> 状态:⬜ 待更新 \| ✅ 已更新 \| ➖ 不涉及 + +## 3. 一致性抽查 + +> 文档写完后随机抽查若干处,确认与代码一致。 + +| 抽查项 | 对应代码 | 一致 | +|-------|---------|------| +| 接口参数名 | | ⬜ | +| 错误码枚举 | | ⬜ | +| 字段默认值 | | ⬜ | +| 配置项名称 | | ⬜ | + +--- + +## 反例 + +❌ **反例 1:只改代码不改文档** +> 加了新字段,文档里没有。半年后别人按文档对接失败。 + +❌ **反例 2:文档写成 commit message** +> "修复 bug"、"优化性能" — 外部用户看不懂。 + +✅ **原则** +> 接口文档站在调用者视角写,说明"做什么 / 怎么调 / 返回什么 / 错了怎么看"。 + +❌ **反例 3:只改一处忘其他** +> 改了 `apis/cvm/RunInstances.md`,忘了更新 `apis/index.md` 和 `architecture.md` 里的调用链图。 + +✅ **原则** +> 用本阶段的清单逐项打钩,防止遗漏。 + +--- + +## 完成标志 + +- [ ] 必检清单每项已明确"已更新"或"不涉及" +- [ ] 所有改动明细已标 ✅ +- [ ] 一致性抽查全部通过 +- [ ] 已在 `00-overview.md` Progress 勾选 07. +- [ ] 已与用户完成结束确认 diff --git a/.specs/plans/_template/06-review.md b/.specs/plans/_template/06-review.md new file mode 100644 index 00000000..06a7d131 --- /dev/null +++ b/.specs/plans/_template/06-review.md @@ -0,0 +1,101 @@ +# 08. Review + +> **目的**:人工 / AI 审查兜底,在 Commit 前最后一道关。 +> **参考**:本文件下方自检清单;项目既有约定见 `AGENTS.md`。 + +--- + +## 1. Review 概览 + +| 项 | 值 | +|----|----| +| Reviewer | | +| Review 时间 | | +| MR / PR 链接 | | +| Commit 范围 | | + +## 2. 自检(作者先做) + +> 作者按下方必查项自检,打钩才能发起 Review。 + +### 2.1 安全 +- [ ] SQL 参数化 +- [ ] 无硬编码凭证 +- [ ] 输入校验 +- [ ] 输出转义 +- [ ] 加密使用标准库 + +### 2.2 正确性 +- [ ] 边界条件覆盖 +- [ ] 并发保护 +- [ ] 事务边界清晰 +- [ ] 幂等 / 重试 / 超时 + +### 2.3 可观测 +- [ ] 日志含 trace_id +- [ ] 错误日志含上下文 +- [ ] 指标 / 告警就位 + +### 2.4 可测 / 可维护 +- [ ] UT 覆盖率达标 +- [ ] 命名清晰 +- [ ] 无重复代码 +- [ ] 文档同步 + +## 3. Reviewer 发现的问题 + +| # | 严重度 | 文件:行 | 问题描述 | 建议 | 修复状态 | 修复 commit | +|---|-------|---------|---------|------|---------|-----------| +| 1 | 🔴 高 | | | | ⬜ 待修 / ✅ 已修 | | + +> 严重度:🔴 高(阻塞) \| 🟡 中(需修或明确忽略) \| 🟢 低(可选) + +## 4. 讨论与决议 + +> 非琐碎的争议点记录于此,便于未来追溯。 + +| # | 议题 | 讨论 | 结论 | 决策人 | +|---|------|------|------|-------| +| | | | | | + +## 5. 最终结论 + +- [ ] 所有 🔴 高严重度问题已修复 +- [ ] 所有 🟡 中严重度问题已修复 **或** 有书面忽略理由 +- [ ] 🟢 低严重度问题已评估 +- [ ] Reviewer 批准合入 + +**Reviewer 签字**(或评论链接): + +--- + +## 反例 + +❌ **反例 1:作者 Review 作者** +> 没有第二人看过代码就合入。 + +✅ **原则** +> 至少一个其他人(或 AI 作为辅助)完整走过清单。 + +❌ **反例 2:Nit-pick 阻塞** +> 为了变量命名争论半天,真正的并发 bug 没人看。 + +✅ **原则** +> 严重度分层,高问题优先;低问题可选 / 另开任务。 + +❌ **反例 3:忽略问题没理由** +> "这个问题暂时不改" — 未来接手者看不到原因。 + +✅ **改写** +> "问题 X 暂不修复,原因:改动影响面大,需评估性能回归,已登记 ADR-0015,预计下迭代处理。" + +--- + +## 完成标志 + +- [ ] 作者自检全部打钩 +- [ ] Reviewer 发现的问题全部有处置(修复或记录) +- [ ] 讨论决议已归档 +- [ ] Reviewer 批准 +- [ ] 已在 `00-overview.md` Progress 勾选 08. +- [ ] 已与用户完成结束确认 diff --git a/.specs/plans/_template/07-commit.md b/.specs/plans/_template/07-commit.md new file mode 100644 index 00000000..38846668 --- /dev/null +++ b/.specs/plans/_template/07-commit.md @@ -0,0 +1,128 @@ +# 09. Commit + +> **目的**:提交代码 + 推送远端 + 创建 MR。 +> **前置条件**(详见 `cvm-tapd` SKILL.md / `cvm-dev-workflow` skill / `SKILL.md` 红线 4):① AI 已主动询问 TAPD ② 本任务专用环境已释放 ③ TAPD 状态已推到「开发中」(CVM 流程时)。 +> **全程不记录 git / TAPD 系统可查的元数据**——commit ID / push 时间 / MR 链接 / amend 次数 / CR 状态 都在 GitLab / `git log` / TAPD 系统里能查,本文件**不重复**。 +> **全流程 3 阶段**:Phase 0 前置收尾(0.0-0.2)→ Phase 1 准备 commit 内容(§1 步骤 1-2,完成后**边界点 A** 锁定)→ Phase 2 执行 commit + push 触发 CR(§1 步骤 3-5,仅一次)→ Phase 3 可选 amend(§1 步骤 6,仅改代码,可反复直到 MR 合入,**边界点 B** 最终锁定)。 + +--- + +## 0. 前置条件 + +### 0.0 进入 commit 时必先询问 TAPD(AI 必执行) + +> **进入本阶段时,AI 必须主动询问用户是否有 TAPD 需求单**——不要直接看 Meta 字段就当有 / 没有。**没有则引导用户创建**(不是简单"问一下"就跳到下一步)。 + +询问话术(**默认推荐路径 A**): +> "本次任务是否已有 TAPD 需求单? +> 1. **有** → 请提供 TAPD 单号(或 `00-overview.md` Meta `Issue / TAPD` 字段已填则直接取) +> 2. **没有** → 建议创建: +> - **路径 A(推荐)**:授权我用 `cvm-tapd` skill 创建——**详细**填充 `02-plan.md` 的方案设计(不是摘要)+ `04-ut.md` 的自测报告(完整测试结果;有测试环境的项目另含 `06-it.md`),并一步步把状态扭转到 **待发布**(方案已评审 → 排期中 → 开发中 → CR → 需求转测 / 待发布) +> - **路径 B**:你自己在 TAPD 端创建,我提供详细字段模板 + 状态推进步骤 +> - **路径 C**(**需记原因到关键决策备忘**):非 CVM 项目 / 本次不需要 TAPD" + +| 情况 | 跳到 | +|------|------| +| 用户有 TAPD 单号(路径 1) | 「0.2 TAPD 状态推进」 | +| 用户选路径 A | AI 调 `cvm-tapd` `stories_create` 填**详细**方案设计(`02-plan.md §1 + §4 + §5` 全文)+ 自测报告(`04-ut.md` §1-§3 完整结果;有测试环境的项目另含 `06-it.md`)→ 一路推到 **待发布**(含 4 步 手动 / 4 步 自动流转)→ 创建完成后回填 Meta → 跳「0.2 TAPD 状态推进」 | +| 用户选路径 B | AI 输出**详细**字段模板 + 状态推进步骤给用户;用户创建+推进后提供 ID → 跳「0.2 TAPD 状态推进」 | +| 用户选路径 C | 在 `00-overview.md` 关键决策备忘记原因 → **跳过整个「0.2 TAPD 状态推进」节**,进 §1 执行顺序 | +| 用户说"暂不处理" | **暂停 commit**,提示用户先处理完再回来 | + +> ❌ **禁止**:跳过询问直接走 Meta 字段;或问完后不引导创建就当"未提供 ID"沉默通过。 + +| # | 动作 | 入口 | 结果记录 | +|---|------|------|---------| +| 1 | **询问 TAPD** | AI 主动问 | 见「0.0」节落地(4 种情况) | +| 2 | 释放本任务专用环境 | `cvm-dev-workflow` skill | 填实下面「0.1 环境释放」表 | +| 3 | 推进 TAPD 状态到「待发布」 | `cvm-tapd` skill | 填实下面「0.2 TAPD 状态推进」表 前 3 行(其余 4 步在 push 后由系统自动 / 手动流转) | + +### 0.1 环境释放 + +| 项 | 值 | +|----|----| +| 环境名 / 环境 ID | | +| 释放命令 | `cvm-envx release -e ` | +| 释放时间 | YYYY-MM-DD HH:MM:SS | +| 结果 | ⬜ 成功 / ❌ 失败(原文 + 用户是否同意带病 commit)/ N/A(未创建环境)+ 原因 | + +### 0.2 TAPD 状态推进(commit 前必推进到「开发中」;最终目标「待发布」) + +> **本节覆盖 TAPD 全链路 7 个状态**(含分支)。**前 3 步 commit 前必推进**——写入本表 + 必填字段(**详细**方案设计 / 详细自测报告,不能只填摘要)。**后 4 步**由 push + 后续流转触发——**不写入本表**(本文件 `git add` 后即冻结),**以 TAPD 系统为唯一来源**;任务收尾前用 `cvm-tapd` 查一次真实状态确认已到 待发布。 + +| 步骤 | 起始状态 | 目标状态 | 触发 | 结果 | 时间 | +|------|---------|---------|------|------|------| +| 1 | 方案设计中 | 方案已评审 | 创建时自动 | ⬜ 成功 / ❌ 失败 | | +| 2 | 方案已评审 | 排期中 | 手动 | ⬜ 成功 / ❌ 失败 | | +| 3 | 排期中 | 开发中 | 计划开始 ≤ today 自动 / 手动 | ⬜ 成功 / ❌ 失败 | | +| 4 | 开发中 | CR | MR 提交后自动 | — 系统可查 — | | +| 5a | CR | 需求转测 | CR 通过 + 仅产研自测=否 | — 系统可查 — | | +| 5b | CR | 待发布 | CR 通过 + **仅产研自测=是**(跳过 需求转测) | — 系统可查 — | | +| 6 | 需求转测 | 待发布 | 测试完成 + 灰度验证 | — 系统可查 — | | + +> **前 3 行**全部 `⬜ 成功` 才能进 §1「1. 执行顺序」步骤 1;任一 `❌ 失败` → 修字段后重试。 +> **后 4 行**(含分支 5b)由 TAPD 系统在 commit + push + 后续流转中自动 / 手动推进,**不**写回本表——本文件在 §1 步骤 3 `git add` 后即冻结(边界点 A)。**任务收尾前**用 `cvm-tapd` 查一次真实状态确认已到 **待发布**。 +> 完整 check 字段(含「详细方案设计」「自测报告」字段映射)见 `cvm-tapd` SKILL.md。 + +--- + +## 1. 执行顺序 + +> **两个边界点(铁律)**: +> - **边界点 A — 内容锁定**:步骤 1+2(写 commit message + 更新 `00-overview.md`)**都完成**之后,**禁止**再改 `00-overview.md` 和 `09-commit.md`——commit 的内容已经定稿。 +> - **边界点 B — MR 锁定**:MR 合入(或用户明确宣布任务收尾)后,**禁止**再有任何改动。 +> - **唯一例外**:边界点 A 与 B 之间,若需要「代码修复」(步骤 6),走 amend——**仅改代码本身**,**不**改 `00-overview.md` / `09-commit.md` / 任何 plans 产物;amend 可反复,**始终只有一个 commit**。 + +| # | 动作 | 结果 | +|---|------|------| +| 1 | 写 commit message | 落「2. 本次实际 Commit」节 | +| 2 | **更新 `00-overview.md`** | 时间记录 09 行**结束时间**(= "所有 prep 写完" 时刻)+ 耗时;关键决策备忘追加 `Commit: ` + `TAPD: @ CR` + 关键变更点;Meta 状态 ✅;Progress 勾选 09(**不**写 commit ID)——步骤 1+2 完成 = **边界点 A** | +| 3 | 一次性 `git add` | 所有变更文件(代码 + plans + docs) | +| 4 | `git commit`(**首次仅一次**) | 用「2. 本次实际 Commit」节的 message | +| 5 | `git push` + 创建 MR | 推远端产生 MR 后,**TAPD 系统自动**「开发中 → CR」;若 CI 通过且无需修复,进 **边界点 B** | +| 6 | **(可选,可反复) 代码修复** | CI 失败 / review 意见 / follow-up 修复:改代码 → amend(§2)→ force-push;**仅改代码,不碰 md 文件**;可反复直到 MR 合入 | + +> 一个 MR 一个 commit(任何修正走步骤 6 amend,**禁止**新增第二个 commit);amend 后 push 用 `--force-with-lease`(**禁止**裸 `--force`)。详见 `SKILL.md` 红线 4。 + +--- + +## 2. amend 流程(步骤 6 = 代码修复,可反复) + +> **amend 只改代码本身**——`00-overview.md` / `09-commit.md` / 任何 plans 产物**冻结到底**,不通过 amend 改写。git / TAPD 系统已经是这些信息的唯一来源(MR 链接 / commit hash / CR 状态 都在 GitLab / `git log` / TAPD 系统里能查)。 + +```bash +git add -A # 仅 add 改动的代码 +git commit --amend --no-edit # 沿用原 commit message +git push --force-with-lease # ✅ 必用;禁止裸 --force +``` + +> **可反复执行**——只要还没到边界点 B(MR 合入),每次修复都走同一套 amend 流程,**不限次数**,但**始终只有一个 commit**,且**只动代码不动 md**。 +> **MR 合入(或用户明确宣布任务收尾)后立即进入「边界点 B — MR 锁定」**——不再 amend,再有任何改动需另开新任务 / 新 MR。 + +--- + +## 3. 本次实际 Commit(commit 前必须填实) + +``` +(): + + + +--= # 默认 --story=;bug fix 改 --bug= +``` + +> ✅ 本节定稿即触发**边界点 A**——**禁止**再动本节(包括 amend)。 + +--- + +## 完成标志 + +> **本清单只含"边界点 A 之前"可勾选的项**——本文件和 `00-overview.md` 一起随 §1 步骤 3 `git add` 进 commit,**add 之后本文件即冻结**。边界点 A 之后的动作(add / commit / push / amend / CI / 合入)**不在本文件打勾**——执行时向用户口头汇报即可,需要查时去 GitLab / `git log` / TAPD 系统查。 + +- [ ] 「0.0 询问 TAPD」已完成:用户给了 ID / AI 代创建 / 用户手动建 / 跳过(4 种之一) +- [ ] 「0.1 环境释放」表已填实(成功 / 失败原文 / 跳过原因) +- [ ] 「0.2 TAPD 状态推进」3 行全部 ⬜ 成功(推进到「开发中」);或非 CVM / 跳过,关键决策备忘已记原因 +- [ ] 「3. 本次实际 Commit」commit message 已落定 +- [ ] **`00-overview.md` 已更新完**(**边界点 A** 触发——09 行结束时间 + 耗时 + 关键决策备忘 commit info;**无** commit ID;Meta ✅;Progress 09 勾选) + +> **边界点 A 之后**(执行动作,不写回本文件,向用户口头确认):一次性 `git add` → `git commit`(首次,仅一次)→ `git push` 产生 MR(**TAPD 系统自动**「开发中 → CR」)→(可反复)CI 失败 / review 意见 → 改代码 → amend + force-push(**只改代码,不碰 md**)→ MR 合入 → 任务收尾前查 TAPD 真实状态确认 CR → 触发**边界点 B**,向用户报告。 diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 00000000..932649f2 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +CODEBUDDY.md \ No newline at end of file diff --git a/CODEBUDDY.md b/CODEBUDDY.md new file mode 100644 index 00000000..151c6018 --- /dev/null +++ b/CODEBUDDY.md @@ -0,0 +1,479 @@ +# . — AI collaboration entry + +> Unified entry for AI collaboration. CodeBuddy / Claude Code / other agents read project conventions and the SOP from here. +> Keep technical docs under `.specs/docs/`, task artifacts under `.specs/plans//`. This file is index + session-recovery protocol only. + +--- + +## 1. Quick index + +| Looking for | Location | +|-----------|---------| +| Architecture, modules, key flows | `.specs/docs/architecture.md` | +| Upstream / downstream / integrations | `.specs/docs/relationship.md` | +| API docs (by module) | `.specs/docs/apis//.md` | +| API docs index | `.specs/docs/apis/index.md` | +| DB / persistence schema | `.specs/docs/sqls/` | +| **Unit-test guide (env / generate / run-debug)** | **`.specs/docs/unittest/unittest.md`** | +| **Integration-test guide (env / cases / run-debug)** | **`.specs/docs/integration_test/integration_test.md`** | +| Local env & startup | `.specs/docs/devops/env.md` | +| Test-env deploy / code sync | `.specs/docs/devops/test-env-deploy.md` | +| All tasks | `ls .specs/plans/` (one directory per task; keep them isolated) | +| Task overview & progress (**single source of truth**) | `.specs/plans/YYYY-MM-DD_/00-overview.md` | +| Per-step task artifacts | `.specs/plans/YYYY-MM-DD_<title>/0N-<step>.md` | + +--- + +## 2. SOP (standard development flow) + +> **Trigger**: when the user describes a requirement / says "start SOP" / "new task: <desc>", enter from Step 1 Clarify and proceed in order. +> **Entry check**: after creating/locating the task directory, if `01-clarify.md` already has real content → skip Clarify and go to Plan (requires user confirmation + mark skipped in `00-overview.md`). + +### Session recovery (required every session) + +> Read this entry file (`AGENTS.md` / `CODEBUDDY.md` / `CLAUDE.md` — same content) → `git branch --show-current` → match branch in `.specs/plans/*/00-overview.md` → read that task's `00-overview.md` → lazy-load the current-step md → report progress. If no match, follow **SOP bootstrap** below. + +### Task isolation (mandatory) + +> **Do not** read or consult any md under other tasks' `.specs/plans/<other-task>/`. Sole exception: the user explicitly says "refer to task X"; never write reference content back into the current task artifacts. + +### SOP bootstrap: branch & task + +> 1. `git branch --show-current`; match under `.specs/plans/`: +> - **Match found** → continue from that `00-overview.md` +> - **No match + on master/main** → `git checkout -b feature/<name> origin/master` → `cp -r .specs/plans/_template .specs/plans/YYYY-MM-DD_<title>` → **strip template comments** → fill Meta → entry check +> - **No match + on feature/** → **Collaborative-dev detection** +> 2. **After copying `_template/` you must strip comments (AI required)**: delete every `<!-- TEMPLATE-ONLY-DO-NOT-COPY: -->` block and the leading "⚠️ TEMPLATE ONLY" section in `plans/<task>/00-overview.md`, replace with a one-line pointer. Rules live only in `_template/` (single source of truth). See the top of `_template/00-overview.md`. +> +> **Do not** run SOP on `master`/`main`. One branch maps to one task directory. + +### Collaborative-dev detection (`design.md`-driven) + +> When the current branch is not master/main and has no task: if `.specs/design.md` exists and the user confirms → fully derive `01-clarify.md` + `02-plan.md` from design.md (do not write only "see design.md") → fill Meta (`开发模式`=协同 / collaborative, plus `测试环境`) → delete design.md → start at Step 3; otherwise use the standard flow. + +### 7 steps + +| # | Step | Artifact | Notes | +|---|------|------|------| +| 1 | **Clarify** | `01-clarify.md` | `skill: clarify` — background / goals / open questions | +| 2 | **Plan** | `02-plan.md` | files to change, call chains, **§6 UT cases (required for TDD)**, IT cases, risks | +| 3 | **Implement** | `03-implement.md` | red-green per Plan §6: failing UT → minimal green → refactor | +| 4 | **UT** | `04-ut.md` | map cases 1:1 to Plan §6; coverage; uncovered lines | +| 5 | **Docs** | `05-docs.md` | incremental updates under `.specs/docs/` | +| 6 | **Review** | `06-review.md` | code-review findings | +| 7 | **Commit** | `07-commit.md` | checklist + full rules in `07-commit.md` (release env / TAPD / commit message / push / amend) | + +### Step execution (common) + +> Each step is **five phases**: confirm start → record start time → execute → record end time → confirm end. +> Write start/end with `date "+%Y-%m-%d %H:%M:%S"` (second precision) into `00-overview.md` (**no backfilling**). End confirmation shows "✅ done + summary + duration + next step" and waits for the user. **Do not** skip steps or merge confirmations without approval. + +### Execution modes + +> All modes share the same 7 steps and artifacts; only confirmation cadence for steps 3–7 differs. Mark mode in `00-overview.md` Meta (`小需求模式` = ✅, etc.). Small-change and standard modes share one table — **auto** means only merge that batch's start/end confirmations into one; **artifacts, timestamps, and Progress checkboxes still apply**. + +| # | Step | Cadence | Small-change mode (≤ 10 LOC) | +|---|------|---------|---------------------------| +| 1 | Clarify | confirm | **confirm** | +| 2 | Plan | confirm | **confirm** | +| 3 | Implement | confirm | **auto** (batch with 04) | +| 4 | UT | confirm | **auto** (batch with 03) | +| 5 | Docs | confirm | **auto** (batch with 05–07) | +| 6 | Review | confirm | **auto** (batch with 05–07) | +| 7 | Commit | confirm | **auto** (batch with 05–07) | + +> Default is the "confirm" column. When Meta `小需求模式` = ✅, use the right column. +> **Auto ≠ skip artifacts**: md artifacts, timestamps, and Progress checks still apply; only merge start/end confirmations ("I'll do 03–04, report once done"). Batch timestamps (03–04 / 05–07 same row & stamp, note "small-change batch") — see `00-overview.md` time-record rule 9. +> **Skip only after asking (05/06)**: AI must ask explicitly; skip only with user OK; write the reason into the step md and mark Progress skipped. Never auto-skip. See completion criteria in `05-deploy.md` / `06-it.md`. +> **Underestimate rollback**: if a "small" change exceeds 10 LOC → set Meta `小需求模式` back to ⬜; confirm 05/06 under standard mode. +> **Collaborative mode**: if `.specs/design.md` exists and the user confirms → skip Clarify/Plan (derive `01-clarify.md` + `02-plan.md` from design.md), start at Step 3; see **Collaborative-dev detection** above. + +--- + +# AGENTS.md + +Navigation guide for AI coding agents working in this repository. + +## 1. Collaboration principles + +> Favor caution over speed; trivial tasks may relax these rules. These principles complement [§10 Change workflow](#10-change-workflow) and [§11 Communication](#11-communication). + +### Think before writing + +- State assumptions up front; ask when unsure — do not guess. +- When multiple interpretations exist, list them and let the user choose — do not pick silently. +- Suggest simpler approaches when they exist; push back when appropriate. +- Stop when blocked; name exactly what is unclear. + +### Simplicity first + +- Write the minimum code that solves the problem; no unrequested features, abstractions, or config knobs. +- Do not add defensive error handling for scenarios that cannot realistically happen. +- Trim the diff when it grows unnecessarily large. + +### Surgical edits + +- Touch only lines directly related to the task; do not opportunistically "clean up" nearby code, comments, or formatting. +- Do not refactor working code or unify style just because it differs from yours. +- Unrelated dead code: mention it, do not delete it proactively. +- Remove orphan imports, variables, and functions **you** introduced. + +### Verifiable outcomes + +- Turn tasks into verifiable goals (what to test, which command proves success). +- For multi-step work, sketch a short plan: `step → verify: …` +- Before saying "done", provide verification evidence; the default ship bar is **`make all` green** (see [§6 Run commands](#6-run-commands), [§10 Change workflow](#10-change-workflow)). + +## 2. What this is + +**Octop** — self-hosted AI assistant platform (multi-user, multi-agent). +One Python wheel: FastAPI backend + React dashboard + Click CLI. +No external queue. No required services beyond an LLM provider. + +## 3. Tech stack + +| Layer | Technology | +|-------|-----------| +| Language | Python 3.12+ | +| Web framework | FastAPI + uvicorn | +| Async runtime | asyncio (no threads except `run_in_executor`) | +| Database | SQLite via sync `sqlite3` (WAL) **or** PostgreSQL via `psycopg` / `psycopg_pool` | +| LLM runtime | `harness-agent` (LangGraph) at `/workspace/harness-agent` | +| Gateway | `harness-gateway` at `/workspace/harness-gateway` | +| Frontend | React 18 + TypeScript + Vite | +| Package manager | uv — always `uv run pytest`, never bare `pytest` | +| API docs UI | Scalar (`scalar-fastapi`) at `/api/docs` | + +## 4. Package layout + +High-level tree — see [§5 Module boundaries](#5-module-boundaries) for what each folder owns and what it may import. + +``` +Octop (`octop/` workspace directory) Python package root (`src/octop/`) + config.py + launch.py composition root: OctopServer + FastAPI + uvicorn + i18n/ locale JSON bundles + tr() + domain helpers + infra/ domain core (agents, DB, gateway, …) + api/ HTTP adapters (FastAPI) + cli/ Click commands + dashboard/ built SPA artifact — do NOT edit + +dashboard/ frontend source (Vite) — edit here +docs/ human-written reference (e.g. `api.md`) +tests/ pytest (`unit/`, `integration/`) +``` + +## 5. Module boundaries + +**Rule of thumb:** dependencies flow **inward** — transport layers call domain; domain never calls HTTP/CLI. Within `infra/`, leaf modules (`utils/`, `db/repos/`, `errors.py`) stay free of higher-level orchestration. + +### Layer overview + +``` +dashboard/ ──HTTP──► api/ ──► infra/ ──► infra/utils/, octop.config +cli/ ──► launch.py ──► api/ + infra/ +``` + +| Layer | Role | May import | Must NOT import | +|-------|------|------------|-----------------| +| `octop.config` | Env-based `OctopConfig` | stdlib, pydantic | `infra/`, `api/`, `cli/`, `launch.py` | +| `octop.i18n` | Locale JSON + `tr()` + per-namespace helpers | `infra/utils/locale`, stdlib | `api/`, `cli/`, `dashboard/` | +| `octop.launch` | Wire `OctopServer`, `build_app`, uvicorn for `octop run` | `infra/`, `api/` | business logic; must not be imported by `infra/` | +| `infra/utils/` | Pure helpers (paths, ulid, env files, Ollama) | stdlib, third-party | any other `infra/*` domain code | +| `infra/db/repos/` | One repo per table — SQL only | `infra/db/_base`, `infra/utils/` | `agents/`, `gateway/`, `api/`, orchestration | +| `infra/` (domain) | Business logic & orchestration | `infra/utils/`, `infra/db/`, `octop.config`, peer `infra/*` subpackages, `infra/errors`, `infra/metrics` | `api/`, `cli/`, `launch.py`, `dashboard/` | +| `api/` | HTTP: routing, auth, SSE, OpenAPI | `infra/`, `octop.config`, sibling `api/*` | `cli/`, `launch.py`; no business rules that belong in `infra/` | +| `cli/` | Terminal UX | `infra/`, `octop.config`, `launch.py`, sibling `cli/*` | `api/`; domain logic duplicated from `infra/` | +| `dashboard/` | React UI | `dashboard/src/api` → backend over HTTP | Python packages; no direct DB or `infra/` access | + +**Hard bans** + +- `infra/` → `api/`, `cli/`, or `launch.py`. +- `api/` → `cli/` or `launch.py`. +- `cli/` → `api/` (use `launch.py` for `octop run` instead). +- `infra/db/repos/` → any non-DB `infra` package. +- `infra/utils/` → any non-utils `infra` package. +- Routers/helpers in `api/routers/` must stay thin: validate HTTP, call `infra/`, map errors — not new domain rules. + +### `infra/` subpackages + +| Path | Owns | Typical importers | +|------|------|-------------------| +| `infra/agents/` | Agent registry (`manager.py`), harness runtime, provider store (`providers/`), settings stores (`security/`, `acp_settings`, `langfuse`), MBTI personas, expert catalog (`experts/`) | `server.py`, `gateway/`, `api/routers/agents.py` | +| `infra/backend/` | Workspace storage adapter, resolver, remote probe (COS/S3/…) | `agents/`, `api/routers/workspace*.py` | +| `infra/connectors/` | Connector catalog, OAuth, MCP gateway, credential crypto | `api/routers/connectors.py`, `internal_mcp.py`, `agents/manager.py` (MCP assembly) | +| `infra/cron/` | Cron jobs, triggers, agent tool hooks | `server.py`, `api/routers/cron.py` | +| `infra/db/` | `SqlitePool`, migrations, `RepoBundle` / `SharedServices` in `services.py` | all domain code needing persistence | +| `infra/gateway/` | IM ingress (`processor.py`), threads, slash commands (`slash/`), bot setup (`bot_creators/`) | `server.py`, `api/routers/chat.py`, `channels.py` | +| `infra/setup/` | First-run wizard, system service install, TLS / Let's Encrypt | `server.py`, `launch.py`, `api/routers/setup.py`, `api/routers/tls.py` | +| `infra/users/` | Users, roles, password hashing, `UserManager` | `server.py`, `api/routers/auth.py`, `users.py` | +| `infra/errors.py` | `OctopError`, `ErrorCode` — shared exception types | everywhere in `infra/` and `api/` | +| `infra/metrics.py` | In-process counters (`METRICS`) | lazy-import inside hot paths | +| `infra/server.py` | `OctopServer.start()` — wires infra singletons | `launch.py`, `api/app.py` | + +### `launch.py` + +| Path | Owns | Must NOT | +|------|------|----------| +| `launch.py` | `run_foreground` / `run_foreground_blocking` — boot `OctopServer`, serve via uvicorn + `build_app`, clean shutdown | HTTP routes, SQL, CLI argument parsing | + +Only `launch.py` may import both `infra/server` and `api/app` in the same module. + +### `api/` layout + +| Path | Owns | Must NOT own | +|------|------|--------------| +| `api/app.py` | FastAPI factory, router registration, static dashboard mount | domain rules, SQL | +| `api/deps.py`, `api/jwt_tokens.py` | JWT extraction, `current_user`, `get_server` | agent lifecycle, cron logic | +| `api/middleware/` | JWT gate, setup lockdown | business validation beyond auth/setup | +| `api/openapi_meta.py` | Scalar tags, API intro text | route handlers | +| `api/errors.py` | Map `OctopError` → HTTP status + JSON | new error semantics (add to `infra/errors.py`) | +| `api/routers/` | One resource per module; Pydantic request/response models | persistence, harness calls — delegate to `infra/` | +| `api/routers/browser/` | Browser session/stream/harness HTTP surface | Playwright logic (stays in harness or helpers here only as glue) | + +### `cli/` layout + +| Path | Owns | +|------|------| +| `cli/main.py` | Click entry, command registration | +| `cli/*_cmd.py` | User-facing subcommands | +| `cli/support/db.py` | Offline DB (`open_cli_services`) | +| `cli/support/offline_ops.py` | Local CRUD via repos (thin wrappers) | +| `cli/support/embedded_ops.py` | Short-lived `OctopServer` for runtime ops | +| `cli/support/acting.py` | Resolve `--user` / pinned defaults / agent owner | +| `cli/support/ctx.py` | Root `--user` / `--agent` / `--json` resolution | +| `cli/support/state.py` | Pinned `default_user` / `default_agent` in `cli_state.json` | +| `cli/run_cmd.py` | `octop run` — delegates to `launch.run_foreground_blocking` | +| `cli/init_cmd.py`, `cli/backup_cmd.py` | Local DB bootstrap / backup via `infra/db` | + +**CLI transport layers** (pick one per command; domain rules live in `infra/`, not duplicated in `cli/`): + +| Layer | When | Examples | +|-------|------|----------| +| **Offline** | Read/write local `~/.octop` SQLite only | `user *`, `provider *`, `cron` list/create/delete, `agent list/delete`, `chats` CRUD, `models` presets/list/active, `channel` CRUD, `admin`, `skills` enable/disable | +| **Embedded** | Needs harness/gateway runtime; boots in-process `OctopServer` | `chats send/repl`, `chats get` (history), `cron run-now`, `agent` create/start/stop/reload, `provider test`, `channel test`, `skills list`, `acp` | +| **External** | Talks to OS/daemon directly, no Octop HTTP | `models ollama-*`, channel QR bind (WeCom/WeChat), Feishu bot-creator subprocess | + +No `octop user login` — CLI trusts local filesystem access to `~/.octop`. Pin acting user with `octop config set-user` or root `--user`; pin agent with `octop agent use` or root `--agent`. If `octop run` is already running, config CLI writes take effect after server restart (cron, channels loaded at boot). + +### `dashboard/src/` layout + +| Path | Owns | Must NOT | +|------|------|----------| +| `api/` | Typed fetch wrappers (`request.ts`, `modules/*`) | UI components, page state | +| `pages/` | Route-level screens and page-local hooks | generic reusable widgets (move to `components/`) | +| `components/` | Shared UI building blocks | direct `fetch` (use `api/` modules) | +| `hooks/` | Reusable React hooks | page-specific one-off logic | +| `context/` | App-wide React context (agent, auth, …) | API calls without going through `api/` | +| `layouts/`, `routes/` | Shell, sidebar, route table | business logic | +| `locales/` | i18n strings | — | +| `utils/` | Frontend pure helpers | API or server knowledge | + +Frontend talks to Octop **only** via `/api` HTTP — never import or assume Python module layout. + +## 6. Run commands + +```bash +make install-hooks # once per clone: enable .githooks pre-commit +make all # format-all + lint + typecheck + test (ship bar) +make format-all # backend Ruff + dashboard Prettier write +make lint # ruff check + format check +make typecheck # mypy --strict src/octop +make format # ruff auto-fix + format (backend only) +make format-frontend # prettier write (dashboard only) +uv run pytest -m "not live" # full test suite (no LLM calls) +uv run pytest tests/unit -x -q # unit tests only, stop on first fail +uv run pytest tests/integration -x -q # integration tests only +cd dashboard && npx tsc --noEmit # frontend typecheck (after UI changes) +make build-frontend # dashboard/ → src/octop/dashboard/ +``` + +**Git hooks (required for local commits):** after cloning, run **`make install-hooks`** once. That sets `core.hooksPath=.githooks` so every `git commit` runs **`make all`** (which first runs **`format-all`**: backend Ruff + dashboard Prettier write, then lint / typecheck / test) and dashboard **`npm run build`**. Formatted files that were already staged are re-added so the commit includes the formatted content. Bypass only in emergencies: `SKIP_PRECOMMIT=1 git commit …` or `git commit --no-verify`. Do **not** skip hooks to land red tests — fix the suite first (CI runs on Linux **and** Windows). + +## 7. Key patterns + +**DI:** Routers receive `server: OctopServer = Depends(get_server)`; core services live on `server.services` (`SharedServices` from `infra/db/services.py`). Never import repos at module level outside `SharedServices` / `RepoBundle`. + +**Agent scope:** Most agent routes use `/api/agents/{agent_id}/…` in the URL. A few legacy endpoints (e.g. MBTI) still take `X-Octop-Agent-Id`. Always validate ownership: load the agent row → `_assert_agent_owner(row, user)` (or admin bypass). + +**Agent workspace I/O:** All reads/writes of agent workspace **content files** go through `HarnessAgent.workspace` (`BackendWorkspace` from `harness-agent`). Do **not** use `agent.backend` directly, `resolve_harness_backend`, or `Path.write_text` / `read_text` on `~/.octop/agents/<id>/` for workspace content. Do **not** branch on backend type or `virtual_mode` in Octop — path rules live in `BackendWorkspace`. + +| Context | Entry | +|---------|--------| +| HTTP (agent must be running) | `require_running_workspace()` in `api/common/workspace.py` | +| Gateway / IM / media | `harness_workspace_for_agent()` in `infra/gateway/process/agent_resolve.py` | +| Agent startup seed (SOUL, expert, plugins) | `agent.workspace` after `_start_agent` | + +**Path conventions:** Pass workspace-relative paths to `BackendWorkspace` (`SOUL.md`, `skills/foo/SKILL.md`). Directory listing defaults to `"."` (current workspace directory). `"/"` is a distinct backend-root path inside `BackendWorkspace` — do **not** conflate it with `"."` there. The dashboard may send leading-`/` paths; HTTP adapters normalize those in `workspace_api_path()` before calling `BackendWorkspace`. + +**Chat attachments:** Dashboard uploads go to `{workspace}/inbound/` via `api/common/attachments.py` + `api/routers/uploads.py`, not a separate `~/.octop/uploads/` store. + +**Database:** Add columns via a new numbered migration +(`infra/db/migrations/00N_description.sql` **and** matching +`00N_description.pg.sql` for PostgreSQL), then bump the version +assertion in `tests/unit/db/test_db_pool.py` (currently `v == 1`). + +**Slash commands:** `infra/gateway/slash/dispatcher.py` routes; `handlers/` implements; catalog in `catalog.py`. + +**Internationalization (i18n):** Supported locales are **`zh`** and **`en`** (`en` is the fallback). User-facing text produced by the **server** (slash replies, IM/channel status, API error messages, tool display names, CLI output) must come from backend bundles — not hard-coded English in `infra/` when the string is shown to end users. + +Backend layout (`src/octop/i18n/`): + +``` +i18n/ + loader.py load JSON, lookup(), tr() — dot-path resolve + format + en.json, zh.json canonical bundles; keep key trees identical across locales + domains/ one module per top-level JSON namespace + errors.py errors.* → error_message() + tools.py tools.* → tool_display_name(), all_tool_labels() + channel.py channel.* → channel_tool_hint_start/end() + slash.py slash.* → tr() with short keys, field_label, localized_rows +``` + +**Lookup rules** + +- Use full paths with `from octop.i18n import tr`, e.g. `tr("slash.catalog.help.label", locale)`. +- Prefer `octop.i18n.domains.<ns>` (or re-exports on `octop.i18n`) for repeated namespaces — e.g. `tool_display_name()`, `error_message()`. +- Slash handlers use `from octop.i18n.domains.slash import tr` (short keys like `"help.title"`). +- Interpolation uses Python `str.format` placeholders (`{name}`, `{tool_name}`). + +**Locale resolution** (`infra/utils/locale.py`): stored user preference wins, then `Accept-Language` (dashboard sends this on API calls), then channel-type hints (IM platforms default `zh`, `telegram` → `en`). Use `resolve_user_locale()` in gateway/IM paths; `resolve_request_locale()` in HTTP handlers. + +**API errors:** `ErrorCode` values map to `errors.<CODE>` in JSON. `OctopError.to_envelope(locale=…)` and the global exception handler localize `message`. Dashboard mirrors codes under `apiErrors.*` in `dashboard/src/locales/{en,zh}.json` — tests require backend and frontend keys to match. + +**IM channels:** Tool names and hint lines must be localized in `stream_project.py` — pass localized `tool_name` and pre-formatted `tool_hint_text` on `MessageEvent.tool_start/end` (harness-gateway reads `tool_hint_text` when present). Do not rely on English `ChannelConstraints.tool_hint_template` alone. + +**Frontend split** + +- **Dashboard chrome** (nav, forms, buttons): `dashboard/src/locales/{en,zh}.json` via i18next. +- **Server-owned copy** (tools, apiErrors): canonical in `src/octop/i18n/*.json`; dashboard keeps copies synced (see `tests/unit/i18n/`) and may hydrate tools from `GET /api/i18n/tools`. + +**Adding strings (checklist)** + +1. Add the same key to `en.json` and `zh.json` under the right namespace (`slash`, `errors`, `tools`, `channel`, …). +2. Add or extend a `domains/*.py` helper when the namespace is used in multiple call sites. +3. If the key is an `ErrorCode` or `apiErrors` entry, update both backend `errors` and dashboard `apiErrors`. +4. Run `uv run pytest tests/unit/i18n -q` (key parity + domain helpers). + +Do **not** use gettext (`.po` files). Do **not** embed user-visible English in `infra/` when a backend i18n key exists. Expert catalog (`infra/agents/experts/`) still uses embedded `label_zh`/`label_en` in source data — out of scope unless explicitly migrating that catalog. + +**Timezone (config.json):** + +User-facing datetime display and cron/scheduling defaults MUST use the server timezone from `config.json` → `default_timezone` (env override `OCTOP_DEFAULT_TIMEZONE`; legacy `cron_timezone` / `OCTOP_CRON_TIMEZONE` still accepted) — not the browser's local timezone. + +| Layer | Entry | +|-------|--------| +| Config | `OctopConfig.default_timezone` in `config.py` | +| API | `GET /api/settings/timezone` → `{ "timezone": "…" }` (`GET /api/cron/settings` remains a compat alias) | +| Dashboard | `useServerTimezone()`; format with `formatServerDateTime` / `formatServerIsoDateTime` / `formatMessageTime(..., timeZone)` in `dashboard/src/utils/formatMessageTime.ts` | + +**Do not** use bare `toLocaleString()` / `toLocaleDateString()` / `toLocaleTimeString()` for timestamps users see without passing the server `timeZone`. Number grouping via `Number#toLocaleString()` (e.g. download counts) is fine. + +**Language:** Keep the existing locale resolution (user preference → `Accept-Language` / dashboard i18n → channel hints → `DEFAULT_LOCALE`). Language is **not** a `config.json` key — do not add one unless explicitly requested. + +**Workspace storage:** `infra/backend/resolver.py` resolves harness `BackendProtocol` from agent config; remote backends use `probe.py` for fast tree listing. Docker sandbox (`type: "docker"` / storage `kind=docker`) uses `sandbox_scope` + `sandbox_prefix` (Octop default `octop_sandbox`) — see `docs/agent-backend-file-io.md` §13. + +**Connectors:** `infra/connectors/` — catalog, OAuth registry, MCP gateway; HTTP surface in `api/routers/connectors.py`. + +**Metrics:** `from octop.infra.metrics import METRICS` — lazy-import inside functions to avoid circular imports. + +**API docs:** Interactive docs live at `/api/docs` (Scalar, backed by `/api/openapi.json`). When adding or changing API routes, keep the generated docs readable for humans: + +- Use existing `tags` from `api/openapi_meta.py`; add a tag description there when introducing a new group. +- Give every route a short `summary`; use `description` for non-obvious behavior (auth, streaming, side effects). +- Prefer typed `response_model` and Pydantic request bodies over raw `dict`. +- Document non-obvious fields with `Field(..., description="…")`; name models clearly. +- Spot-check `/api/docs` after API changes — a route that renders as an empty card or untyped blob is unfinished. + +**Cross-platform tests:** Octop CI runs on both Linux and Windows, so tests must not assume a single platform: + +- Guard POSIX-only behavior with the repo convention `@pytest.mark.skipif(os.name != "posix", reason="…")`; prefer a module-level `posix_only = pytest.mark.skipif(os.name != "posix", reason="…")` alias. Use `pytest.mark.skipif(os.name == "nt", reason="…")` when a case is Linux/macOS-only for a different reason (e.g. forbidden path characters). +- Do not hard-code POSIX paths (`/`, `/proc`, `/etc`, `/root`, `/usr/bin/…`, `~` → HOME) in assertions that run on every platform — they resolve differently on Windows (e.g. `/` → `D:\`). Prefer opaque mock tokens via `tests.support.fakes.fake_bin_path("tool")` (uses `pathlib` / `os.sep`) when stubbing `shutil.which` / `resolve_binary`. +- Prefer `tmp_path` / `tmp_path_factory` and `pathlib.Path` over OS-specific literals; compare paths with `Path` equality (`tmp_path / "a" / "b"`), not string prefixes with `/`. Use `Path.as_posix()` / `os.sep` only when a serialized path string is part of the contract under test. +- Do not assert `chmod` mode bits, symlink semantics, or Unix-only subprocess shells unless the test is marked `posix_only` (and production code short-circuits on non-POSIX the same way). +- When a feature's semantics are inherently POSIX-only (e.g. the host root_dir denied prefixes in `infra/utils/host_dirs.py`), keep the source guards (`os.name != "posix"` short-circuit) and mirror them in the tests. +- New connector/CLI/gateway tests that materialize files under `OCTOP_HOME` must set `monkeypatch.setenv("OCTOP_HOME", str(tmp_path))` and assert dirs with `Path` joins — never assume `~/.octop/...` string shape. + +## 8. Do not + +Boundary rules are in [§5](#5-module-boundaries). Additionally: + +- Do not import legacy top-level modules — use current paths: + - `octop.agents.*` → `octop.infra.agents.*` + - `octop.channels.*` → `octop.infra.gateway.*` + - `octop.db.*` → `octop.infra.db.*` + - `octop.users.*` → `octop.infra.users.*` + - `octop.utils.*` → `octop.infra.utils.*` (or `octop.infra.metrics` for metrics) + - `octop.errors` / `octop.server` / `octop.shared` → `octop.infra.errors` / `octop.infra.server` / `octop.infra.db.services` +- Do not import `api/` from `infra/` or `cli/` — use `launch.py` to wire HTTP serving. +- Do not put domain logic in `api/routers/` or `cli/*_cmd.py` when it belongs in `infra/`. +- Do not import `infra/db/repos/*` from routers — use `server.services.*_repo` via `infra/` services or managers. +- Do not write bare `pytest` — always `uv run pytest`. +- Do not edit `src/octop/dashboard/` directly — build artifact; source is `dashboard/`. +- Do not add blocking I/O in async functions — use `run_in_executor`. + +## 9. Where to look + +| Question | Location | +|----------|----------| +| How does auth work? | `api/jwt_tokens.py`, `api/deps.py`, `api/middleware/jwt_auth.py`, `api/routers/auth.py` | +| Setup wizard (password file, tokens) | `infra/setup/`, `api/routers/setup.py` | +| TLS / Let's Encrypt | `infra/setup/tls/`, `api/routers/tls.py` | +| `octop run` boot sequence | `launch.py`, `cli/run_cmd.py` | +| How is a message processed? | `infra/gateway/processor.py` → harness agent | +| How are agents started/stopped? | `infra/agents/manager.py`, `infra/agents/runtime.py` | +| How does cron work? | `infra/cron/manager.py`, `infra/cron/job.py` | +| What DB tables exist? | `infra/db/migrations/` + `infra/db/repos/` | +| What env vars are supported? | `config.py` | +| How does the frontend call the API? | `dashboard/src/api/request.ts` | +| Internationalization (backend) | `src/octop/i18n/`, `infra/utils/locale.py`, `api/routers/i18n.py` | +| Internationalization (dashboard) | `dashboard/src/locales/`, `dashboard/src/i18n.ts`, `dashboard/src/utils/apiError.ts` | +| Server timezone (config.json) | `default_timezone` in `config.py`; `GET /api/settings/timezone`; `dashboard/src/hooks/useServerTimezone.ts`; `dashboard/src/utils/formatMessageTime.ts` | +| Test layout & shared helpers | `tests/support/` (`fakes`, `auth`, `http`, `scenarios`, `app`), `tests/integration/conftest.py`, `tests/unit/{db,cron,gateway,agents,api,cli}/` | +| Pre-commit hooks | `make install-hooks` → `.githooks/pre-commit` (`make all` incl. `format-all` + dashboard build) | +| What is a Thread? | `infra/gateway/threads.py`, `infra/db/repos/threads.py` | +| Workspace backend resolution | `infra/backend/resolver.py`, `infra/backend/adapter.py` | +| Connectors & OAuth | `infra/connectors/`, `api/routers/connectors.py` | +| OpenAPI tags and API intro | `api/openapi_meta.py` | +| Human-readable API reference | `docs/api.md` | +| SharedServices / RepoBundle | `infra/db/services.py` | +| Branching & release | [§10](#10-change-workflow) Branching & release; `CONTRIBUTING.md`; `.cursor/skills/publish` | + +## 10. Change workflow + +1. **Clarify scope** — read relevant code/docs; confirm assumptions and ambiguities with the user (see [§1](#1-collaboration-principles)). +2. **Hooks** — if this clone has not run `make install-hooks` yet, do it before committing (see [§6](#6-run-commands)). Pre-commit must stay green (`make all` + dashboard build). +3. **Minimal implementation** — change only task-related files; dashboard source is in `dashboard/`, build output in `src/octop/dashboard/` (run `make build-frontend` after UI changes). +4. **Verify** — backend/ship bar: `make all` (`format-all` + `lint` + `typecheck` + `test`). After `dashboard/` changes, also run `cd dashboard && npx tsc --noEmit` (and `npm run lint` when appropriate). After API route changes, glance at `/api/docs` for readable summaries and schemas. After i18n JSON changes, run `uv run pytest tests/unit/i18n -q`. Treat Windows CI as part of the bar: follow [§7 Cross-platform tests](#7-key-patterns). +5. **Wrap up** — remove orphan symbols introduced in this change; do not commit or push unless asked. + +### Branching & release + +``` +feature/* ──PR──► develop ──► release/x.y.z ──PR──► main ──tag v*──► publish +hotfix/* ──PR──► main (+ tag) and ──PR──► develop +``` + +| Branch | Role | +|--------|------| +| `main` | Production source of truth; **default branch**; only release / hotfix merges; **only `v*` tags on `main` are production** | +| `develop` | Daily integration; **base for feature PRs** | +| `release/x.y.z` | Temporary freeze (version bump / CHANGELOG / bugfixes); **delete after ship** | + +**Rules** + +- Never push `develop` directly onto `main` — ship via `release/*` → `main` (or hotfix → `main`) only. Do **not** bulk-merge `develop` → `main`; it forks history and breaks post-release sync. +- Merge `release/*` → `main` with a **merge commit** (not squash) so `main` stays reconcilable with `develop`. +- Release sequence: cut `release/*` from latest `develop` → PR into `main` → **tag `v*` on main tip only after merge** → delete `release/*` → Actions syncs `main` → `develop` (`sync-main-to-develop.yml`; opens `chore/sync-develop-after-*` on conflict / branch protection). +- Keep **`main` an ancestor of `develop`** after every release. Do not use legacy `head=main` → `develop` sync PRs. +- Do **not** push a production tag from a release/feature branch before it is on `main`. +- Hotfix: branch from `main`, PR to `main` (and tag if shipping), then PR into `develop`. +- Day-to-day feature work: branch from `develop`, open PR **into `develop`** (not `main`). +- Human detail: `CONTRIBUTING.md`. Agent publish flow: `.cursor/skills/publish`. + +## 11. Communication + +- Default to **Chinese** when talking to the user; cite code with `` `path:line` ``. +- Lead with the conclusion, then details; write complete sentences, not telegraphic fragments. +- When marking work done, include verification commands and results (or explain why they were not run). +- Do not pile on unrelated follow-ups; mention out-of-scope issues briefly, do not expand scope unilaterally.