# 三国团队工具链与开发流程设计 > **状态**: v2.0 — 串联架构重构(Gitea 自动化 + Daemon Webhook + Mail 执行层) > **作者**: 庞统(副军师)🐦 > **评审**: 司马懿(仲达)🗡️ > **日期**: 2026-06-06 > **v0.4 变更**: 主公 6 条反馈(需求review前置、E2E用户触发、测试分工、审查默认司马懿、项目维度组织、分支保护说明) > **v0.5 变更**: E2E 改为自动跑(CI隔离环境不污染生产)、三环境架构、schema变更检查确认、分支保护确认开启 > **v0.6 变更**: Agent spawn 走生产 openclaw(不隔离)、程序逻辑走 CI 隔离环境、路径硬编码修复清单 > **定位**: 普适工具链和开发流程,适用于三国团队所有项目,与 moziplus 2.0 解耦 --- ## §1. 设计原则 | # | 原则 | 说明 | |---|------|------| | 1 | **声明式 + 代码执行分离** | 规则声明在配置中,执行由框架代码保证,不依赖 Agent 自觉(来源: moziplus-quality-governance) | | 2 | **能自动就自动** | CI/CD/部署能自动触发就不手动,人只做决策和审查 | | 3 | **Skill 固化流程** | 所有流程通过 Skill(提示词)固化,不靠口头约定 | | 4 | **分级治理** | 按风险级别选择流程严格度,不搞一刀切(来源: quality-gate-patterns) | | 5 | **验证才算完** | Agent 说"完成"不算,CI 通过 + 产出物存在才算(来源: 幻觉门控) | | 6 | **每个项目自带部署** | 部署脚本归项目管,工具链负责触发和验证,不替项目做部署决策 | | 7 | **需求/问题必须经过 Review** | 所有需求和问题提交前必须经过 Review,不直接进入开发 | | 8 | **项目维度组织** | 所有内容(Issue、CI、部署、Skill 配置)以项目为单位组织,支持多项目并行 | --- ## §2. 基础设施层 ### 2.1 代码托管:Gitea(唯一) | 项 | 配置 | |----|------| | 地址 | `http://192.168.2.154:3000` | | 版本 | v1.23.4 | | 认证 | HTTP + token(待配置) | | 权限 | cfdaily 用户;姜维持有 admin 权限(启用 Actions、分支保护等) | ### 2.2 CI/CD:Gitea Actions | 项 | 配置 | |----|------| | Runner | Mac mini 裸机,act-runner(Go 二进制) | | 配置文件 | `.gitea/workflows/*.yml`,每个项目自管 | | 语法 | 兼容 GitHub Actions(v1.23.4 已验证支持) | | 触发 | push / PR / tag | ### 2.3 部署目标 | 环境 | 位置 | 说明 | |------|------|------| | Mac mini 本机 | `~/.sanguo_projects//` | 主力开发和运行环境 | | NAS Docker | `192.168.2.154` | 部分服务(Gitea、回测等) | --- ## §3. 分支策略 ### 3.1 采用 Trunk-Based Development(简化版) 选 Trunk-Based 而非 Git Flow 的理由: - **团队小**(<10 人),不需要复杂的 release 分支 - **AI Agent 参与编码**,Agent 在短生命周期 feature 分支上工作,完成后快速合并 - **CI 是安全网**,main 分支始终可部署,feature 分支通过 CI 才能合并 前提条件:**Agent 必须知道当前所在分支**。git-workflow Skill 需注入 `git branch --show-current` 到 Agent 上下文(仲达 Q1 补充)。 ### 3.2 分支规则 | 分支类型 | 命名 | 生命周期 | 合并方式 | 适用场景 | |---------|------|---------|---------|---------| | `main` | `main` | 永久 | — | 始终可部署 | | feature | `feat/-<简述>` | <3天 | PR → CI → Review → merge | 新功能 | | bugfix | `fix/-<简述>` | <1天 | PR → CI → merge | Bug 修复 | | hotfix | `hotfix/<简述>` | <2小时 | 直接 push main + CI + 自动回滚 | 紧急修复 | ### 3.3 分支保护规则 - `main` 分支: - 不允许直接 push(hotfix 除外) - PR 必须通过 CI(至少 unit + integration tests) - PR 必须至少 1 人 Review(人或 Agent) - **hotfix 直接 push main 后必须触发 CI**(至少 lint + unit),CI 失败则自动 revert(M1 修订) - feature/bugfix 分支: - 无保护,自由 push - 合并前必须 CI 通过 ### 3.4 Commit 规范 ``` (): ``` | type | 说明 | |------|------| | `feat` | 新功能 | | `fix` | Bug 修复 | | `refactor` | 重构(不改行为) | | `test` | 测试相关 | | `docs` | 文档 | | `chore` | 构建/工具/配置 | --- ## §4. 问题管理 ### 4.1 问题来源 | 来源 | 入口 | 处理方式 | |------|------|---------| | 主公口头 | 庞统记录,**经 Review 后** | 创建 Gitea Issue | | 司马懿 Review | Review 意见 | 创建 Gitea Issue,关联 PR | | 自动化测试失败 | CI 报告 | 自动评论到已有 Issue,或手动创建 | | 用户测试反馈 | 人工报告 | 创建 Gitea Issue | | Agent 运行发现 | Agent 日志,**经 Review 后** | 创建 Gitea Issue | ### 4.2 Issue 标签体系 | 标签 | 颜色 | 说明 | |------|------|------| | `bug` | 红 | 功能异常 | | `feature` | 蓝 | 新功能需求 | | `improvement` | 绿 | 改进优化 | | `security` | 橙 | 安全相关 | | `risk:high/standard/low` | 分级色 | 风险级别(见 §6.1 判定规则) | | `priority:high/medium/low` | 黄/灰 | 优先级 | | `blocked` | 紫 | 阻塞中 | ### 4.3 需求/问题 Review 前置 所有需求和问题在进入开发之前必须经过 Review: | 类型 | Review 者 | 目的 | |------|-----------|------| | 新需求 | 庞统(方案合理性)+ 司马懿(技术可行性) | 确认需求清晰、可行、值得做 | | Bug/问题 | 司马懿(确认根因)或庞统(确认优先级) | 确认是真 bug、不是误报,根因明确 | | Agent 发现的问题 | 庞统(确认有效性) | 过滤误报 | 未经过 Review 的 Issue 不进入开发流程。 ### 4.4 Issue 状态流转 ``` Open → In Progress → Review → Closed ↑ ↓ └──── Reopened ←───────────────────┘ ``` --- ## §5. CI/CD 管道设计 ### 5.1 通用 CI 流程(所有项目共享骨架) 每个项目在 `.gitea/workflows/ci.yml` 自定义具体步骤,但遵循统一骨架。 > **注**:Gitea Actions v1.23.4 不支持 `paths` 过滤触发条件。通过路径判断放在 job 级别的 `if` 条件中,使用确定支持的语法。(M4 修订) ```yaml name: CI on: push: branches: [main] pull_request: branches: [main] jobs: # Job 1: 后端测试 backend: # 只在有 Python 代码变更时跑 runs-on: [self-hosted, mac-mini] steps: - uses: actions/checkout@v4 - name: Setup Python run: | python3 -m venv .venv .venv/bin/pip install -e ".[dev]" - name: Lint run: .venv/bin/ruff check src/ - name: Unit Tests run: .venv/bin/pytest tests/unit/ -m "not e2e" --tb=short - name: Integration Tests run: .venv/bin/pytest tests/integration/ --tb=short - name: Coverage Report run: .venv/bin/pytest --cov=src --cov-report=term-missing # Job 2: 前端构建 frontend: # 只在有前端目录时跑 runs-on: [self-hosted, mac-mini] steps: - uses: actions/checkout@v4 - name: Install & Build run: | cd src/frontend npm ci npm run build - name: Type Check run: cd src/frontend && npx tsc --noEmit ``` **实际使用时**:每个项目根据实际情况删减 job。没有前端的删 frontend job,没有 Python 的删 backend job。 ### 5.2 CI 门控级别 | 级别 | 触发条件 | 跑什么 | 阻断行为 | |------|---------|--------|---------| | **快速** | feature 分支 push | lint + unit tests | **软阻断**:失败标红,创建 PR 时如果最近一次 CI 失败则不允许进入 Review(S2 修订) | | **标准** | PR 到 main | lint + unit + integration + coverage | 阻断 merge | | **完整** | tag / main push | 标准 + build(E2E 仅 tag 触发) | 阻断部署 | | **手动** | 手动触发 | 完整 + 特定检查 | 按需 | ### 5.3 覆盖率渐进策略(仲达 Q3 补充) 当前多数项目从未跑过覆盖率,直接设阈值不现实。分三阶段: | 阶段 | 时间 | 覆盖率策略 | 说明 | |------|------|-----------|------| | **P1** | 启用后 2 周 | 只报告不阻断 | 先拿基线数据 | | **P2** | 启用后 1 月 | 40% 阈值,低于警告不阻断 | 逐步提升 | | **P3** | 启用后 2 月+ | 60% 阈值,低于阻断 | 正式生效 | ### 5.4 CI 结果反馈 - ✅ 通过 → PR 可合并 - ❌ 失败 → PR 阻断,自动评论失败信息 - 覆盖率低于阈值 → P1 只报告,P2 警告,P3 阻断 --- ## §6. 代码审查流程 ### 6.1 风险级别判定规则(M2 修订) 风险级别不由改动者自评,按以下规则自动判定 + 非改动者确认: **自动判定规则**(在 CI 或 PR 模板中检查): | 规则 | 级别 | 触发条件 | |------|------|---------| | 涉及核心模块 | **高** | 改动文件匹配 `**/spawner*`、`**/ticker*`、`**/dispatcher*`、`**/router*`、`**/guardrails*`、`**/strategy*`、`**/risk*` | | 涉及资金/安全 | **高** | 改动包含交易逻辑、风控规则、密钥管理、资金操作 | | 数据库 schema 变更 | **高** | 改动匹配 `**/migrations/**`、`**/schema*`、`**/models.py` 中的表定义 | | 常规功能开发 | **标准** | 不匹配高风险规则的 src/ 下改动 | | 文档/测试/配置 | **低** | 改动仅在 `docs/`、`tests/`、`*.md`、`*.yaml`(非 guardrails) | **确认机制**: 1. PR 创建时自动标注风险级别(基于 git diff 文件路径) 2. 审查者(或庞统)确认或升级——**只能升级不能降级** 3. 改动者可以申请升级(但不能申请降级) ### 6.2 审查方式(按风险分级) | 风险级别 | 审查方式 | 审查者 | |---------|---------|--------| | **高** | 固定 Review(必须) | 司马懿(专职) | | **标准** | 固定 Review(必须) | 司马懿(默认审查者) | | **低** | 简化走查 | 司马懿(快速确认)+ CI 通过 | **例外**:司马懿自己的改动 → 庞统交叉审查。 > 所有级别的代码审查默认由司马懿执行。只有司马懿作为改动者时,才由庞统进行交叉审查。不再按改动领域分配审查者——简化流程,减少协调成本。 ### 6.3 审查者分配规则 | 改动者 | 审查者 | |--------|--------| | 张飞 / 姜维 / 关羽 / 赵云 / 庞统 | 司马懿(默认) | | 司马懿 | 庞统(交叉审查) | ### 6.4 审查清单(Skill 固化) 审查清单通过 Skill 提示词固化,不依赖审查者自觉。**基础清单 + 项目类型变体**: **基础清单(所有项目通用)**: ``` 1. 正确性 - [ ] 代码逻辑正确,无死循环/空指针/边界遗漏 - [ ] 异常处理完整(网络超时、文件不存在、参数非法) - [ ] 改动范围和 Issue/需求描述一致(不多不少) 2. 一致性 - [ ] 命名规范统一(变量/函数/文件) - [ ] 和已有代码风格一致 3. 安全性 - [ ] 无硬编码密钥/密码/Token - [ ] 用户输入有校验 - [ ] 文件操作有路径校验 4. 可维护性 - [ ] 复杂逻辑有注释(为什么,不是做什么) - [ ] 无重复代码(DRY) - [ ] 关键参数可配置,无魔法数字 5. 测试覆盖 - [ ] 新功能有对应测试 - [ ] Bug 修复有回归测试 - [ ] CI 通过 结论:通过 / 不通过(附具体行号和修改方向) ``` **量化策略项目变体**(追加项): ``` 6. 量化策略专项 - [ ] 止损逻辑完整(触发条件、执行路径、异常兜底) - [ ] 仓位计算正确(滑点、手续费已计入) - [ ] 回测参数和实盘参数分离 ``` ### 6.5 审查时效 | 改动大小 | 期望审查时间 | |---------|-------------| | < 100 行 | 2 小时内 | | 100-500 行 | 半天内 | | > 500 行 | 1 天内 | --- ## §7. 部署流程 ### 7.1 部署触发 | 触发方式 | 适用场景 | 流程 | |---------|---------|------| | **自动**(tag 触发) | 正式发布 | 打 tag → CI 完整跑(含 E2E)→ 自动执行 deploy 脚本 → 健康检查 | | **自动**(main push) | 日常迭代 | push main → CI 标准跑 → 自动执行 deploy 脚本 → 健康检查 | | **手动** | 紧急/调试 | 手动执行项目 deploy 脚本 | ### 7.2 项目部署脚本规范 每个项目必须提供 `scripts/deploy.sh`,接口统一: ```bash #!/usr/bin/env bash # deploy.sh — 项目部署脚本 # # 必须支持的参数: # --source=DIR 源码目录(CI 自动传入:源码 checkout 路径) # --target=DIR 安装目标目录(CI 自动传入:安装路径) # --skip-build 跳过构建步骤 # --health-check 部署后执行健康检查 # --version 输出当前部署版本(tag + commit hash + 部署时间) # --rollback 回滚到上一个已记录的部署版本 # # 必须维护的文件: # data/deploy-history.jsonl — 最近 10 个部署版本记录 # 每行: {"tag":"v1.2.3","commit":"abc123","timestamp":"2026-06-06T12:00:00+08:00","status":"success"} # # 必须返回: # 0 = 成功 # 非0 = 失败(stderr 输出原因) ``` ### 7.3 自动部署 Workflow ```yaml # .gitea/workflows/deploy.yml name: Deploy on: push: branches: [main] tags: ['v*'] jobs: deploy: needs: [ci] # 依赖 CI 通过 runs-on: [self-hosted, mac-mini] steps: - uses: actions/checkout@v4 - name: Record current version run: bash scripts/deploy.sh --version - name: Deploy run: bash scripts/deploy.sh --source="$GITHUB_WORKSPACE" --health-check - name: Rollback on failure if: failure() run: bash scripts/deploy.sh --rollback ``` ### 7.4 健康检查 每个项目的 deploy 脚本必须包含健康检查: - HTTP 服务:`curl -sf http://localhost:/api/health` - 数据服务:数据连通性检查 - 定时任务:PM2 状态检查 ### 7.5 回滚策略(M3 修订) **版本记录**: - 每次 deploy 成功后,记录 tag + commit + 时间戳到 `data/deploy-history.jsonl`(保留最近 10 条) - `--version` 读取最后一行输出当前版本 - `--rollback` 读取倒数第二行,checkout 对应 commit,重新 deploy **回滚流程**: 1. `deploy.sh --rollback` 读取上一个成功版本 2. `git checkout ` 3. 重新执行 deploy(不含 rollback) 4. 健康检查 **已知限制**: - revert 可能产生合并冲突 → 部署失败时人工介入 - 数据库变更回滚需人工介入 → schema 变更必须向前兼容(只加字段不删/不改),违反此规范由 CI 检查拦截(或人工 Review 拦截) --- ## §8. 验证流程集成 ### 8.1 验证来源和层级 | 验证来源 | 层级 | 触发时机 | 自动化程度 | |---------|------|---------|-----------| | **Lint** | 机械 | 每次 push | 100% 自动 | | **单元测试** | 机械 | 每次 push | 100% 自动 | | **集成测试** | 语义 | PR 到 main | 100% 自动 | | **覆盖率** | 语义 | PR 到 main | 渐进自动(见 §5.3) | | **Code Review** | 共识 | PR 到 main | 人工(Skill 辅助) | | **E2E 测试** | 共识 | PR 到 main 时自动跑(CI 隔离环境)+ 手动触发 | 自动+手动 | | **用户测试** | 共识 | 部署后 | 手动 | ### 8.2 三阶段门控(来源: quality-gate-patterns) ``` 机械门控 (CI 快速) → 语义门控 (CI 标准 + Review) → 共识门控 (E2E + 用户验证) 零成本 中等成本 高成本 语法/lint/编译 API 契约/业务逻辑 端到端/用户体验 ``` - 快速门控是**开发期辅助反馈**,不替代标准门控 - **PR 合入必须经过标准门控(机械 + 语义)**,这个顺序不可跳过(S3 修订) - 机械失败 → 立即阻断,不看 Review - 语义失败 → 可以 Review 但不能合并 - E2E 在 CI 隔离环境中自动跑,不污染生产环境(见 §8.5)。也可手动触发。 ### 8.3 测试失败 → Issue 关联 - CI 失败时,如果已有 Issue → 自动评论失败信息 - CI 失败时,如果无 Issue → 不自动创建(避免 Issue 爆炸),由改动者手动创建 ### 8.4 机械门控前提条件(仲达 Q6 补充) P1 必须先配好以下工具,否则机械门控跑不起来: | 工具 | 用途 | 安装 | |------|------|------| | `ruff` | Python lint + format | `pip install ruff` | | `pytest-cov` | 覆盖率 | `pip install pytest-cov` | | `act-runner` | CI 执行器 | 下载 Go 二进制 | ### 8.5 CI 隔离测试环境(E2E 安全运行) E2E 自动跑的核心前提:**不污染生产环境**。通过 CI 隔离环境实现: ``` CI 临时测试环境(每次 CI 自动创建) ├─ 独立 venv(每次 CI 新建) ├─ 临时 SQLite(tmpdir,跑完销毁) ├─ 临时端口(8084,不和生产 8083 冲突) ├─ 启动 FastAPI 服务 → 跑 E2E → 关闭 └─ 跑完整个 tmpdir 删除,不留痕迹 生产环境(~/.sanguo_projects/)完全不受影响 ``` **效果**:E2E 可以在每次 PR 到 main 时自动跑,无需担心污染生产数据或影响生产服务。 #### 隔离边界:程序逻辑 vs Agent 交互 | 层面 | 隔离方式 | 说明 | |------|---------|------| | **程序逻辑**(FastAPI + Daemon + SQLite) | ✅ 完全隔离 | 独立 venv + 临时数据库 + 临时端口 | — | | **Agent spawn**(openclaw agent) | ❌ 走生产 openclaw | openclaw 是全局单例,无法隔离 | 测试 case 用 UUID 前缀标识 + Agent 回写地址指向 8084 临时端口 | Agent spawn 走生产 openclaw 的决策理由: 1. openclaw 是全局单例(`~/.openclaw/` 只有一份),Agent 配置和 workspace 全局共享 2. 测试 case 会标识测试上下文,Agent 记忆混淆风险低 3. 完全隔离需要在 Docker 中跑独立 openclaw,维护成本不值得 4. Agent 的 API 回写地址由 spawn message 传入,指向 CI 临时服务的端口 8084 #### 路径硬编码修复清单 当前代码有 6 处硬编码绝对路径,需改为环境变量可配置(P1 必须完成): | 位置 | 硬编码路径 | 改法 | 现状 | 行数 | |------|-----------|------|------|------| | `utils.py` | 数据根目录 | `BLACKBOARD_ROOT` 环境变量 | ✅ 已支持 | 1 | | `bootstrap.py:42` | Skill 加载路径 | `MOZI_SKILL_PATH` 环境变量 | ✅ 已支持 | 1 | | `registry.py:264` | 项目扫描目录 `~/.openclaw/sanguo_projects` | 加 `SANGUO_PROJECTS_DIR` | ❌ 硬编码 | 1 | | `spawner.py:1177,1261` | `~/.openclaw/agents//sessions.json` | 加 `OPENCLAW_HOME` | ❌ 硬编码 | 2 | | `blackboard_routes.py:161` | `~/.openclaw/openclaw.json` | 从 `OPENCLAW_HOME` 读 | ❌ 硬编码 | 1 | 共计 6 处(2 已支持、4 待修)。 #### 环境总结 | 环境 | 位置 | 用途 | 生命周期 | |------|------|------|---------| | 开发 | `~/.openclaw/sanguo_projects/` | 改代码、本地调试 | 常驻 | | CI 测试 | CI runner 临时目录 | lint/unit/integration/E2E | CI 跑完即销毁 | | 生产 | `~/.sanguo_projects/` | 正式运行服务 | 常驻 | **schema 变更检查**(可选):CI 中加一步对比数据库 schema 变更,检测破坏性操作(删字段/改类型)。检测到则提 Issue 人工确认。可通过配置开关强制绕过。 --- ## §9. 完整开发流程(端到端) ### 9.0 全局工作流串联图 以下是把所有关键环节串起来的完整链路。三个场景(新功能/Bug修复/Hotfix)共享大部分节点,差异在分支。 ``` ┌─────────────────────────────────────────────────────────────────────────┐ │ 问题/需求入口 │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ 主公口头 │ │ CI 失败 │ │ 司马懿 │ │ 运行时 │ │ │ │ /需求文档 │ │ 自动报告 │ │ Review │ │ Agent发现 │ │ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ └──────────────┴──────────────┴──────────────┘ │ │ ↓ │ │ ┌─────────────────────┐ │ │ │ 需求/问题 Review │ ← §4.3 │ │ │ │ │ │ │ 需求: 庞统(方案) │ │ │ │ + 司马懿(可行) │ │ │ │ Bug: 司马懿(确认根因)│ │ │ │ Agent发现: 庞统(过滤)│ │ │ └──────────┬──────────┘ │ │ ↓ 通过 │ │ ┌───────────────────────────────────────────────────────────┐ │ │ │ 创建 Gitea Issue #N │ │ │ │ 标签: bug/feature/improvement + risk:high/standard/low │ │ │ │ 关联: PR / 复现步骤 / 根因分析 │ │ │ └──────────────────────────┬────────────────────────────────┘ │ │ ↓ │ │ ┌──── 场景分流 ────┐ │ │ ↓ ↓ │ │ ┌─── Hotfix ───┐ ┌── 标准流程 ──┐ │ │ │ │ │ │ │ │ │ 直接 main │ │ 分支开发 │ │ │ │ │ │ │ │ │ └──────┬───────┘ └──────┬───────┘ │ │ ↓ ↓ │ └─────────────────────────────────────────────────────────────────────────┘ === 标准流程(新功能 / Bug修复)=== ┌─────────────────────────────────────────────┐ │ Step 1: 分支创建 │ │ git checkout -b feat/issue-N-xxx │ │ 或 git checkout -b fix/issue-N-xxx │ │ 角色Agent: 开发者(张飞/姜维/关羽/赵云) │ │ Skill: git-workflow │ │ 输入: Issue #N │ │ 输出: feature/bugfix 分支 │ └──────────────────┬──────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ Step 2: 编码 + 自测 │ │ 编码 → 本地 pytest → commit │ │ 角色Agent: 开发者 │ │ Skill: 按任务类型(无专门编码skill) │ │ 输入: 分支 + Issue 需求 │ │ 输出: 代码改动 + UT │ │ 约束: Bug修复必须加回归测试 │ └──────────────────┬──────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ Step 3: push → CI 快速门控(每次push) │ │ Lint + Unit Tests │ │ 工具: Gitea Actions │ │ 输入: feature 分支 push │ │ 输出: ✅通过 / ❌失败标红 │ │ 阻断: 软阻断(失败不阻止开发,但阻止PR进入Review)│ └──────────────────┬──────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ Step 4: 创建 PR │ │ git push origin → Gitea 创建 PR │ │ 自动: 风险级别标注(按改动文件路径) │ │ 工具: Gitea PR │ │ 输入: feature 分支 + CI 快速门控结果 │ │ 输出: PR + 风险标签 │ └──────────────────┬──────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ Step 5: CI 标准门控(PR到main时) │ │ Lint + Unit + Integration + Coverage │ │ 环境: CI 隔离临时环境 │ │ 工具: Gitea Actions + pytest-cov + ruff │ │ 输入: PR diff │ │ 输出: ✅通过 / ❌阻断merge │ │ 阻断: 硬阻断(CI不过不许merge) │ └──────────────────┬──────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ Step 6: 代码审查 │ │ 审查者确认风险级别(只升不降) │ │ 默认审查者: 司马懿(所有级别) │ │ 例外: 司马懿的改动 → 庞统交叉审查 │ │ Skill: code-review │ │ 输入: PR + CI 结果 + 风险级别 │ │ 输出: 通过 / 不通过(附行号+修改方向) │ │ 不通过 → 回到 Step 2 │ └──────────────────┬──────────────────────────┘ ↓ 通过 ┌─────────────────────────────────────────────┐ │ Step 7: Merge → CI 完整门控 │ │ merge到main → 自动触发 │ │ 标准 CI + deploy workflow │ │ 触发: Gitea branch protection(CI+Review通过才许merge)│ │ 输入: main 分支 │ │ 输出: merge commit + CI 结果 │ └──────────────────┬──────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ Step 8: 自动部署 │ │ deploy.sh --source=... --health-check │ │ 记录版本到 deploy-history.jsonl │ │ 角色Agent: 姜维(deploy.sh由项目维护) │ │ Skill: ci-cd-ops │ │ 输入: main 分支代码 │ │ 输出: 部署结果 + 版本记录 │ │ 失败: 自动回滚(deploy.sh --rollback) │ └──────────────────┬──────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ Step 9: E2E 验证(CI 隔离环境自动跑) │ │ 临时venv + 临时SQLite + 临时端口8084 │ │ Agent spawn 走生产 openclaw(不隔离) │ │ 角色: 司马懿写E2E用例,CI自动跑 │ │ Skill: testing-workflow │ │ 输入: 部署后的代码 │ │ 输出: E2E 结果 │ │ 阻断: 初期不阻断,成熟后可阻断 │ └──────────────────┬──────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ Step 10: Issue 关闭 │ │ 部署成功 + 验证通过 → 关闭 Issue #N │ │ 发现新问题 → 新开 Issue → 回到入口 Review │ └─────────────────────────────────────────────┘ === Hotfix 分支流程 === ┌─────────────────────────────────────────────┐ │ Step H1: 确认 hotfix │ │ 庞统或主公确认(线上故障、核心功能受影响) │ │ Skill: hotfix-workflow │ └──────────────────┬──────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ Step H2: 直接 push main │ │ 修改 → commit → push main │ │ CI 必须触发(lint + unit),不可跳过 │ │ CI 失败 → 自动 revert → 人工介入 │ └──────────────────┬──────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ Step H3: 自动部署(同标准 Step 8) │ │ E2E 验证(同标准 Step 9) │ └──────────────────┬──────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ Step H4: 24h 内复盘(必须) │ │ 补 Gitea Issue(根因 + hotfix 内容) │ │ 司马懿 Review(事后审查代码质量) │ │ 复盘记录(为什么需要 hotfix、如何避免) │ │ 超时 → 下次 hotfix 权限暂停 │ └─────────────────────────────────────────────┘ ``` #### 衔接机制:每一步怎么触发下一步 上图只画了"谁做什么",这里补清楚**步骤之间靠什么机制衔接**。 | 衔接点 | 触发方式 | 通知方式 | 技术实现 | |--------|---------|---------|----------| | 问题入口 → 问题Review | 庞统收到问题后主动发起 | Mail 通知司马懿(需求类)/ 司马懿自己提交(bug类) | Mail API POST `/api/mail` | | 问题Review → Issue创建 | Review结论达成 | 庞统或司马懿创建 | Gitea API `POST /repos/{owner}/{repo}/issues` | | Issue创建 → 分支创建 | 庞统指派任务给开发者 | Mail 通知被指派者,含 Issue #N + 分支名 | Mail API + Agent 读取 Issue | | 分支创建 → 编码 | 开发者看到 Mail 后开始 | 无额外通知 | Agent 启动时 Skill 注入分支信息 | | 编码 → CI 快速门控 | **git push 自动触发** | CI 结果显示在 commit 状态(Gitea Status Check 内置) | Gitea Actions `on: push` | | CI 快速门控 → PR创建 | 开发者主动(认为代码写完) | 无自动通知 | 开发者在 Gitea Web UI 或 git push + 浏览器创建 PR | | PR创建 → CI 标准门控 | **PR 创建/更新自动触发** | CI 结果自动评论到 PR | Gitea Actions `on: pull_request` | | CI 标准门控 → 代码审查 | **CI 通过后 daemon Webhook 转发 Mail 给审查者** | Mail 通知司马懿 Review | Gitea Webhook `pull_request` → daemon Webhook 模块 → Mail API | | 代码审查 → 修改(不通过) | 审查者提交 Review 意见 | daemon Webhook 转发 Mail 通知改动者(附 Review 摘要) | Gitea Webhook `pull_request_review` → daemon Webhook 模块 → Mail API | | 代码审查 → Merge(通过) | **审查者点 Approve** | daemon Webhook 转发 Mail 通知改动者 merge | Gitea Webhook `pull_request_review` → daemon Webhook 模块 → Mail API | | Merge → 部署 | **merge 到 main 自动触发** | 无需通知(自动化) | Gitea Actions `on: push: branches: [main]` | | 部署 → E2E | **部署 job 成功后触发 E2E job** | E2E 结果评论到 merge commit | Gitea Actions `needs: [deploy]` | | E2E/部署 → Issue关闭 | 庞统或改动者手动确认后关闭 | Issue 关闭通知关注者 | Gitea API `PATCH /repos/{owner}/{repo}/issues/{id}` state=closed | | CI失败 → Issue评论 | **CI 失败自动评论** → daemon Webhook 转发 Mail 通知改动者 | 评论到关联 Issue + Mail 推送 Agent | Gitea Actions `if: failure()` 写 PR评论 → daemon Webhook 监听 `issue_comment` → Mail | | 部署失败 → 自动回滚 | **deploy.sh 失败自动执行** | 无需通知(自动化) | Gitea Actions `if: failure()` step 调 `deploy.sh --rollback` | #### 关键衔接机制详解 **1. Gitea Actions 自动触发(核心衔接)** 整个 CI/CD 链路的自动化靠 Gitea Actions 的触发机制: ``` git push feature分支 → Gitea Actions on: push 匹配 → 跑 lint + unit(快速门控) 创建 PR → Gitea Actions on: pull_request 匹配 → 跑 lint + unit + integration + coverage(标准门控) → CI 结果自动出现在 PR 页面 Merge 到 main → Gitea Actions on: push: branches: [main] 匹配 → 跑 deploy workflow(含 deploy.sh + health check + E2E) → 全自动,无需人干预 ``` 触发链:push → CI → PR → CI → Review → merge → deploy+E2E,中间三个自动环节靠 Gitea Actions 的 `on` 触发器串联。 **2. Mail 通知(Agent 间协调)** CI/CD 之外的衔接靠 Mail。Agent 不会自己去看 Gitea PR 评论,所以所有需要 Agent 行动的情况都通过 Mail 推送: - 需求Review完成 → Mail 通知开发者开始 - Bug确认 → Mail 通知改动者(含根因) - Hotfix确认 → Mail 通知执行者 - CI 失败 → CI workflow 写 PR 评论 → daemon Webhook 模块转发 Mail 通知改动者 Agent - 审查不通过 → Mail 通知改动者(附 Review 摘要) - 部署失败回滚 → Mail 通知庞统/姜维(人工介入) **3. Gitea branch protection(硬门控)** 确保流程不可跳过: - `main` 分支设置:CI 必须通过 + 至少 1 人 Review Approve - 效果:没有 CI 绿勾 + Review Approve,merge 按钮灰色不可点 - 配置位置:Gitea → 仓库 Settings → Branches → Branch Protection **4. Agent 间通知机制总结** | 场景 | 通知方式 | 为什么不用另一种 | |------|---------|----------------| | 人→Agent任务指派 | Mail | Gitea Issue 不会主动通知 Agent,需要 Mail 推送 | | CI 结果 | Gitea Status Check(PR页面)+ daemon Webhook 转发 Mail(Agent通知) | Status Check 给人看,Mail 给 Agent 推送 | | Review 请求 | daemon Webhook 转发 Mail | Gitea Webhook 触发 → daemon 翻译成 Mail 给司马懿 | | Review 意见(不通过/通过) | daemon Webhook 转发 Mail | Gitea Webhook 触发 → daemon 翻译成 Mail 给改动者 | | CI 失败 | CI workflow 写 PR评论 → daemon Webhook 转发 Mail | CI 写评论是给所有人看,Webhook → Mail 给 Agent 推送 | | 跨Agent协作请求 | Mail | Gitea 不支持跨 Agent 私信 | ### 9.0.1 通知模板(工具链通用版) 以下为 §9.0 衔接机制中用到的通用通知模板。§15.5 中还定义了更详细的流程强约束 Mail 模板(含完整流程步骤和 Gitea API 调用指令)。 所有自动化通知统一格式,确保 Agent 收到后能直接行动。 **模板 1:任务指派(庞统 → 开发者)** ``` From: pangtong-fujunshi To: {被指派者} Title: 任务指派: Issue #{N} - {Issue 标题} Text: {Issue 标题} Issue: http://192.168.2.154:3000/{repo}/issues/{N} 分支: feat/issue-{N}-{简述} 风险级别: {high/standard/low} 要点: - {需求要点1} - {需求要点2} 验收标准: - {验收标准1} - {验收标准2} ``` **模板 2:CI 失败通知(CI workflow → 改动者)** ``` From: daemon-webhook To: {PR 作者} Title: CI 失败: PR #{N} - {PR 标题} Text: PR #{N} CI 未通过。 PR: http://192.168.2.154:3000/{repo}/pulls/{N} 失败测试: - {test_path}::{test_name} FAILED - {test_path}::{test_name} FAILED 失败 step: {step_name} 错误摘要: {error_output_tail_20_lines} 请修复后重新 push。 ``` **模板 3:Review 不通过通知(审查者 → 改动者)** ``` From: {审查者} To: {改动者} Title: Review 不通过: PR #{N} - {PR 标题} Text: PR #{N} 审查未通过。 PR: http://192.168.2.154:3000/{repo}/pulls/{N} 风险级别: {confirmed_level} 审查意见: 1. [{文件}:{行号}] {问题描述} → {修改方向} 2. [{文件}:{行号}] {问题描述} → {修改方向} 必须全部修改后重新 push。 ``` **模板 4:部署失败回滚通知(CI workflow → 庞统/姜维)** ``` From: daemon-webhook To: pangtong-fujunshi, jiangwei-infra Title: 部署失败已回滚: {repo} {commit_hash} Text: {repo} 部署失败,已自动回滚到上一版本。 触发 commit: {commit_hash} 部署脚本: scripts/deploy.sh 失败原因: {deploy_stderr_tail} 当前版本: {previous_version} 请人工介入排查。 ``` **模板 5:Bug 确认通知(司马懿 → 改动者)** ``` From: simayi-challenger To: {改动者} Title: Bug 确认: Issue #{N} - {Issue 标题} Text: 根因: {根因描述} 复现步骤: {steps} 影响范围: {scope} 风险级别: {level} Issue: http://192.168.2.154:3000/{repo}/issues/{N} 分支: fix/issue-{N}-{简述} 请修复并添加回归测试。 ``` ### 9.1 场景 A:新功能开发 ``` 1. 问题入口 └─ 主公口头 / 需求文档 └─ 庞统梳理需求方案 → 司马懿确认技术可行性 └─ Review 通过后 → 庞统创建 Gitea Issue #N 2. 分支创建 └─ git checkout -b feat/issue-N-xxx └─ Agent 或人工编码(git-workflow Skill 注入分支信息到 Agent 上下文) 3. 开发过程中 └─ 每个 commit → push → CI 快速门控(lint + unit) └─ CI 失败 → 标红但不阻断开发 → 修好再 push 4. 开发完成 └─ git push origin feat/issue-N-xxx └─ 创建 PR → 自动标注风险级别(基于改动文件路径) └─ CI 标准门控(lint + unit + integration + coverage) 5. 审查 └─ CI 通过后进入审查 └─ 审查者确认风险级别(只升不降) └─ 司马懿审查(所有级别默认) └─ 如果改动者是司马懿 → 庞统交叉审查 └─ 审查不通过 → 修改 → push → CI → 再审 └─ 审查通过 → merge 6. 部署 └─ merge 到 main → 自动触发 CI + deploy workflow └─ deploy.sh 执行 → 记录版本 → 健康检查 └─ 部署成功 → Issue #N 关闭 └─ 部署失败 → 自动回滚 → 人工介入 7. 验证 └─ CI 隔离环境中自动跑 E2E(不污染生产) └─ 用户测试(手动) └─ 发现问题 → 新开 Issue(经 Review 后再开发) ``` ### 9.2 场景 B:Bug 修复 ``` 1. 问题入口 └─ CI 失败 / 司马懿 Review / 运行时发现 └─ 司马懿确认根因(是真 bug 不是误报) └─ 创建 Gitea Issue #N,标注 bug + 风险级别 2. 根因定位(bugfix-workflow Skill) └─ 调查根因(不猜,看日志/复现) └─ 在 Issue 中记录根因 3. 修复 └─ git checkout -b fix/issue-N-xxx └─ 修改代码 + 添加回归测试(必须) └─ push → PR → CI → Review 4. 合并+部署 └─ merge → auto deploy → 健康检查 └─ Issue #N 关闭 5. 验证 └─ 确认原 bug 不再复现 ``` ### 9.3 场景 C:紧急修复(hotfix)(M1/S5 修订) ``` 1. 判断是否需要 hotfix └─ 标准:线上故障影响核心功能,等 PR 流程代价过高 └─ 庞统或主公确认 2. 直接在 main 上修 └─ git commit → push main └─ CI 必须触发(lint + unit),不可跳过 └─ auto deploy → 健康检查 └─ CI 失败 → 自动 revert → 人工介入 3. 事后复盘(hotfix-workflow Skill) └─ 24 小时内必须完成: ├─ 补 Gitea Issue(记录根因 + hotfix 内容) ├─ 司马懿 Review(事后审查代码质量) └─ 复盘记录(为什么需要 hotfix、如何避免) └─ 超时未复盘 → 下次 hotfix 权限暂停 4. E2E 验证 └─ CI 隔离环境中自动跑 E2E 确认 hotfix 有效 ``` --- ## §10. Skill 清单(流程固化)(S4 修订) 以下流程通过 Skill 固化到对应 Agent: | Skill 名 | 固化什么 | 适用 Agent | |----------|---------|-----------| | `git-workflow` | 分支创建/命名/合并规范、commit 规范、PR 创建流程、**当前分支注入上下文** | 所有编码 Agent | | `code-review` | 风险级别判定规则、审查清单(基础+项目变体)、审查标准、结论格式 | 司马懿(默认审查者)、庞统(交叉审查) | | `ci-cd-ops` | CI 配置规范、deploy 脚本规范、健康检查标准、版本记录规范 | 姜维(平台)、所有项目维护者 | | `bugfix-workflow` | 根因定位流程、回归测试要求、Issue 关联 | 所有编码 Agent | | `hotfix-workflow` | hotfix 判断标准、直接 push main 流程、CI 必跑、24h 复盘要求 | 庞统(协调)、张飞、姜维 | | `testing-workflow` | 测试分工规范、什么时候跑什么测试、测试数据隔离 | 所有 Agent | | `release-workflow` | tag 规范、changelog、发布流程、数据库 schema 变更向前兼容规范 | 庞统(协调) | ### 测试分工规范(testing-workflow Skill 内) | 测试类型 | 谁写 | 谁跑 | |---------|------|------| | **单元测试(UT)** | 开发者自己(张飞/姜维/关羽/赵云等) | CI 自动 + 开发者本地 | | **功能测试** | 司马懿(专职) | CI 自动 | | **集成测试** | 司马懿(专职) | CI 自动 | | **E2E 测试** | 司马懿(专职) | CI 自动(隔离环境)+ 手动触发 | | **测试脚本/工具** | 司马懿 + 赵云(数据相关) | 按需 | > 所有人都能写代码和写 UT。但功能测试、集成测试、E2E 由司马懿专职编写和维护——确保测试视角独立于开发视角。 --- ## §11. 实施路线 | 阶段 | 内容 | 前置条件 | 耗时 | |------|------|---------|------| | **P0: 基础启用** | Gitea admin 开启 Actions + 部署 act-runner(Mac mini 裸机) | 主公操作 NAS | 30 分钟 | | **P1: CI 骨架** | 模板 CI workflow + pytest-cov + ruff + 覆盖率基线测量 | P0 | 1 天 | | **P2: 流程 Skill** | 7 个 Skill 编写(见 §10) | 无 | 2-3 天 | | **P3: 自动部署** | 部署 workflow + 项目 deploy.sh 规范化 + 版本记录 | P1 | 1-2 天 | | **P4: 渐进收紧** | 覆盖率阈值 P1→P2→P3、E2E 集成 | P1-P3 | 按需 | **P1 必须先就位的工具**(否则机械门控跑不起来): - `ruff`(lint) - `pytest-cov`(覆盖率) - `act-runner`(CI 执行器) --- ## §12. 评审记录 ### v0.1 → v0.2 修订清单 | 编号 | 类型 | 问题 | 修订内容 | |------|------|------|---------| | M1 | 必须修 | hotfix 安全网不足 | §3.3 明确 hotfix push main 后 CI 必跑,失败自动 revert;§9.3 统一流程 | | M2 | 必须修 | 风险级别谁来定 | §6.1 新增自动判定规则(按文件路径)+ 非改动者确认机制(只升不降) | | M3 | 必须修 | 回滚策略过于简单 | §7.2 新增 `--version` 参数和 deploy-history.jsonl;§7.5 重写回滚策略 | | M4 | 必须修 | CI 语法问题 | §5.1 删除 `hasPython()`/`hasFrontend()` 伪函数,改为每个项目按需删减 job | | S1 | 建议改 | 轮查配对不合理 | §6.3 改为按改动领域分配,不再固定轮转 | | S2 | 建议改 | 快速门控"不阻断"是噪音 | §5.2 改为"软阻断",PR 进入 Review 前检查最近 CI 状态 | | S3 | 建议改 | 三阶段门控说明不清 | §8.2 补充:快速门控是开发辅助,PR 合入必须标准门控 | | S4 | 建议改 | Skill 遗漏 | §10 增加 testing-workflow、hotfix-workflow、release-workflow(含 schema 变更) | | S5 | 建议改 | hotfix 复盘无时限 | §9.3 加 24 小时复盘约束,超时暂停 hotfix 权限 | | Q1 | 评审回答 | Trunk-Based 够用吗 | §3.1 补充前提:Agent 必须知道当前分支,git-workflow Skill 注入 | | Q3 | 评审回答 | 覆盖率基线缺失 | §5.3 新增渐进策略(P1 只报告 → P2 40% → P3 60%) | | Q6 | 评审回答 | 机械门控前提未就绪 | §8.4 新增工具清单,§11 标注 P1 必须先就位 | ### v0.3 → v0.4 修订清单(主公审阅反馈) | 编号 | 反馈 | 修订内容 | |------|------|---------| | F1 | 需求/问题必须经 Review | §1 新增原则 7;§4.3 新增需求 Review 前置规则;§9.1 场景 A 加入 Review 步骤 | | F2 | E2E 仅用户触发 | §8.1 E2E 改为“仅用户手动触发”;§8.2 门控说明移除 E2E 自动跑;§9.1/9.3 验证步骤更新 | | F3 | 编码/测试人人能做,功能/集成/E2E 司马懿专职 | §10 新增测试分工规范表 | | F4 | 审查默认司马懿 | §6.2 简化为司马懿统一审查,仅司马懿自身改动由庞统交叉审查 | | F5 | 以项目为单位组织 | §1 新增原则 8;Issue 标签体系含项目维度 | | F6 | 姜维持有 Gitea admin | §2.1 权限更新 | | F7 | 分支保护含义说明 | §3.3 补充分支保护规则说明 | | F8 | schema 变更能自动化就自动化 | 保留在 release-workflow,CI check + Issue 兜底 | ### v0.4 → v0.5 修订清单(主公二次审阅) | 编号 | 反馈 | 修订内容 | |------|------|----------| | G1 | E2E 不自动跑是因为怕污染生产,不是不需要 | §8.5 新增 CI 隔离测试环境,E2E 改为自动跑(临时 venv + 临时 SQLite + 临时端口) | | G2 | 三套环境是否有必要 | §8.5 环境总结表:开发/CI临时/生产,不需要常驻测试环境 | | G3 | schema 变更检查可以,可选+开关 | §8.5 补充 schema 检查说明:可选 + 配置开关强制绕过 | | G4 | 分支保护确认开启 | §14 更新为已确认 | | G5 | E2E 触发方式 | §8.1 更新:CI 自动 + 手动触发 | ### v0.5 → v0.6 修订清单(主公三次审阅) | 编号 | 反馈 | 修订内容 | |------|------|----------| | H1 | Agent spawn 走生产 openclaw,不隔离 | §8.5 新增隔离边界表:程序逻辑隔离 vs Agent 走生产 | | H2 | 路径硬编码问题 | §8.5 新增路径硬编码修复清单(6 处,2 处已支持、4 处待修) | ### v0.6 → v1.0 定稿(司马懿终审通过) - 隔离边界表增加"缓解措施"列(仲达建议) - 路径硬编码清单增加"行数"列(仲达建议) - 状态标记为 v1.0 定稿 ### v1.0 → v1.1(主公要求:补全局工作流串联图) - §9.0 新增全局工作流串联图:从问题入口到部署上线的完整链路 - 每个节点标注:谁做、用什么工具、什么Skill、输入输出 - 标准流程 10 步 + Hotfix 分支 4 步 - 新增工具链衔接总览表 - 新增衔接机制详解:每一步怎么触发下一步、靠什么技术、怎么通知 - §9.0.1 新增 5 个通知模板(任务指派/CI失败/Review不通过/部署回滚/Bug确认) - 修正:Agent 不看 Gitea PR 评论,所有需 Agent 行动的场景都走 Mail 推送 ### v1.2 → v2.0(串联架构重构) - §15 新增完整串联架构:Gitea 自动化 + Daemon Webhook 模块 + Mail 执行层 - 核心变更:ci-notifier 取消,Webhook 转发集成到 daemon - 新增:超时检测(三级处置)+ 失败处置(走 Issue 流程) - 新增:Mail 模板(流程强约束固化) - 新增:Skill vs Mail 边界明确 - 新增:Agent ID ↔ Git 用户名映射 - §9.0 衔接机制表更新:所有 ci-notifier 引用替换为 daemon Webhook 模块 - §9.0.1 通知模板 From 字段更新:ci-notifier → daemon-webhook ### v2.0 司马懿终审修订 | 编号 | 类型 | 问题 | 修订内容 | |------|------|------|----------| | M1 | 必须修 | 超时阈值统一 4h 不合理 | §15.4 改为从 Mail metadata 读取个性化 deadline,三级处置按超时程度而非绝对时间 | | S1 | 建议 | Webhook 代码缺少映射步骤 | §15.3 代码示例加 to_agent_id() 映射函数,所有 send_mail 调用都经映射 | | S2 | 建议 | Webhook 缺签名验证 | §15.3 代码示例加 X-Gitea-Signature HMAC 验证 | | S3 | 建议 | 缺 Bug 确认模板 | §15.5 新增模板 6(Bug 确认通知) | - §14 待讨论更新:已确认事项标记,新增 Webhook 模块待讨论项 --- ## §13. 项目维度组织 ### 13.1 多项目并行 所有内容以项目为单位组织: | 维度 | 按项目组织 | |------|------------| | **代码仓库** | Gitea 上每个项目一个 repo | | **Issue** | 每个项目的 Issue 独立管理 | | **CI/CD** | 每个项目自管 `.gitea/workflows/` | | **部署脚本** | 每个项目自管 `scripts/deploy.sh` | | **测试** | 每个项目自管 `tests/` 目录 | | **Skill 配置** | 通用 Skill 共享,项目特定 Skill 放项目仓库 | 特殊:`_general` 项目用于跨项目的通用任务(如工具链基础设施维护)。 --- ## §14. 待讨论 1. **Gitea admin 权限**:姜维持有 admin 权限,可负责启用 Actions、配置分支保护等 2. **分支保护**:已确认开启——PR 必须 CI 通过 + 至少 1 人 Review 才能合并到 main 3. **数据库 schema 变更检查**:CI 自动检测破坏性变更(可选,有开关可强制绕过),检测不到的提 Issue 人工干预 — **已确认** 4. **环境架构**:三环境(开发/CI临时/生产),CI 临时环境支持 E2E 自动跑不污染生产 — **已确认** 5. **Webhook 转发模块集成到 daemon**:已确认方向,具体实现待设计(见 §15) --- ## §15. 串联架构 > §15 是 v2.0 的核心新增章节,定义工具链三层串联架构:Gitea 自动化 + Daemon Webhook 模块 + Mail 执行层。 > 此架构取消了之前的 ci-notifier 虚拟角色概念,所有事件流转通过三层清晰分工完成。 ### §15.1 串联架构总览 三层架构图: ``` Layer 1: Gitea 自动化(流程引擎) - Actions: push → CI, PR → CI, merge → deploy - Status Check: CI 结果自动显示在 PR - Branch Protection: CI通过+Review通过才许merge - CI workflow 内可调 Gitea API 写 PR 评论 Layer 2: Daemon 流程编排(转发+监控) - Webhook 接收模块:监听 /webhook 端点 - 简单事件:Webhook → 解析 → 直接发 Mail - 复杂事件:Webhook → 解析 → spawn 庞统作为任务节点 - 超时检测:在 ticker 中扫描未回复 Mail - 失败处置:轻度重发提醒,中度 spawn 庞统,严重创建 Issue Layer 3: Mail 执行层(Agent 接口) - Mail = 流程指令 + 回复确认 + 时限 - Agent 收到 Mail 后行动,完成后回复确认 - Mail 线程 = Issue 生命周期可追溯 - 流程强约束固化在 Mail 模板中 ``` 核心原则: 1. **Gitea 是流程引擎**——所有状态流转靠 Gitea 自己(Actions + Status Check + Branch Protection) 2. **Webhook → Mail 转发集成在 daemon 里**——状态共享,可直接触发下一步 3. **Mail 是 Agent 接口**——Agent 不看 Gitea UI,所有需 Agent 行动的事件通过 Mail 推送 4. **简单事件 daemon 直接处理,复杂事件(多 Agent 协作)spawn 庞统作为协调节点** 5. **没有 ci-notifier**——不需要虚拟角色,Gitea 是流程引擎,daemon 是翻译器+监控器 ### §15.2 Gitea Webhook 能力清单 | 事件类型 | 触发时机 | Payload 关键字段 | 工具链用途 | |---------|---------|----------------|-----------| | `push` | 代码推送 | commit hash, 分支, 作者 | 不需要转发(Actions 自动处理) | | `pull_request` (opened) | PR 创建 | PR ID, 标题, 分支, 作者 | → Mail 通知司马懿 Review | | `pull_request_review` (submitted) | Review 提交 | PR ID, 审查者, 结论(APPROVE/REQUEST_CHANGES), 评论 | → Mail 通知张飞 Review 结果 | | `pull_request` (closed/merged) | PR 合并 | PR ID, 合并 commit | 不需要转发(Actions 自动触发 deploy) | | `issue_comment` | PR/Issue 评论 | 评论者, 内容 | CI workflow 写的失败评论 → 转发 Mail | | `issues` (opened+assigned) | Issue 创建/指派 | Issue ID, 标题, 被指派人 | → Mail 通知开发者 | | `release` | Release 创建 | tag, 名称 | 触发完整 CI+部署 | > **说明**:Webhook 是单向 POST,Gitea 发完不管。需要在 daemon 里实现 `/webhook` 端点接收。 ### §15.3 Daemon Webhook 模块设计 在 daemon 中新增一个 Webhook 接收模块(FastAPI 路由): ```python # src/api/webhook_routes.py @router.post("/webhook/gitea") async def handle_gitea_webhook(event: dict, x_gitea_event: str = Header(...), x_gitea_signature: str = Header(None)): """接收 Gitea Webhook,翻译成 Mail 或 spawn 庞统""" # 签名验证(防止伪造) if x_gitea_signature and WEBHOOK_SECRET: expected = hmac.new(WEBHOOK_SECRET, json.dumps(event).encode(), sha256).hexdigest() if not hmac.compare_digest(expected, x_gitea_signature): raise HTTPException(403, "Invalid webhook signature") # Git 用户名 → Agent ID 映射 def to_agent_id(git_username: str) -> str: return GIT_TO_AGENT.get(git_username, git_username) if x_gitea_event == "pull_request": action = event["action"] if action == "opened": pr_author = to_agent_id(event["pull_request"]["user"]["login"]) await send_mail(to="simayi-challenger", title=f"Review 请求: PR #{event['number']}", ...) elif action == "closed" and event["pull_request"]["merged"]: # merge 不需要通知,Actions 自动处理 pass elif x_gitea_event == "pull_request_review": state = event["review"]["state"] if state == "APPROVED": pr_author = to_agent_id(event["pull_request"]["user"]["login"]) await send_mail(to=pr_author, title=f"Review 通过: PR #{event['number']},请 merge", ...) elif state == "REQUEST_CHANGES": pr_author = to_agent_id(event["pull_request"]["user"]["login"]) await send_mail(to=pr_author, title=f"Review 不通过: PR #{event['number']}", ...) elif x_gitea_event == "issue_comment": # CI 自动写的失败评论 → 转发给相关 Agent if "CI 失败" in event["comment"]["body"]: commenter = to_agent_id(event["sender"]["login"]) await send_mail(to=commenter, title=f"CI 失败: PR #{event['number']}", ...) elif x_gitea_event == "issues": if event["action"] == "assigned": assignee = to_agent_id(event["assignee"]["login"]) await send_mail(to=assignee, title=f"任务指派: Issue #{event['number']}", ...) ``` 关键设计: - 模块部署在 daemon 的 FastAPI 里(已有服务,只加路由) - 和 Mail API 共享 SQLite(直接调内部函数,不经过 HTTP) - 简单事件(CI失败通知、Review通知、任务指派)直接发 Mail - 复杂事件(部署失败、架构级 Review 问题)spawn 庞统 ### §15.4 回复驱动与超时处置 > daemon ticker 中新增两个定时扫描任务,**回复驱动是主路径,超时检测是兜底**。 **主路径:回复驱动(Agent 回复 Mail 后,daemon 根据结果触发下一步)** ```python # daemon ticker 每小时跑一次 async def process_flow(): # 路径1:扫描新回复,驱动下一步(主路径) await check_replies() # 路径2:扫描超时未回复,兜底处置 await check_stale_flows() async def check_replies(): """扫描 Mail 回复,根据结果触发下一步""" # 查所有有新回复的 Mail(回复在上一轮扫描之后) replied_mails = queries.find_recently_replied(since=last_scan) for mail in replied_mails: reply = get_reply(mail.id) if is_success_reply(reply): # 成功 → 记录闭环,不触发动作 # 原因:Gitea 自动化(Actions + Webhook)会自动推动下一步 # 例:张飞回复"已创建PR" → Gitea Webhook 自动通知司马懿 Review # 例:张飞回复"已merge" → Gitea Actions 自动触发 deploy log.info(f"Mail {mail.id} 已成功闭环: {reply.text[:100]}") elif is_failure_reply(reply): # 失败 → 创建 Issue 走正式流程 await create_issue( title=f"执行失败: {mail.title}", labels=["bug"], body=f"原指令: {mail.text}\n\n失败原因: {reply.text}" ) # 通知庞统 await send_mail(to="pangtong-fujunshi", title=f"执行失败已创建 Issue: {mail.title}", ...) elif is_help_reply(reply): # 需协助 → spawn 庞统协调 await spawn_agent("pangtong-fujunshi", f"Agent {reply.from} 执行 '{mail.title}' 遇到困难,请求协助。详情: {reply.text}") ``` **兜底路径:超时检测(Agent 没回复时的处置)** ```python async def check_stale_flows(): """扫描超时未回复的 Mail,按个性化 deadline 判断""" pending_mails = queries.find_pending_requests() for mail in pending_mails: deadline_hours = mail.meta.get("deadline_hours", 8) # 默认 8 小时 hours_elapsed = (now() - mail.created_at).total_seconds() / 3600 if hours_elapsed < deadline_hours: continue # 未超时,跳过 hours_overdue = hours_elapsed - deadline_hours if hours_overdue < 4: # 轻度:重发 Mail 提醒 await send_mail(to=mail.to, title=f"提醒: {mail.title}", text=f"此任务已超时 {hours_overdue:.0f} 小时,请尽快处理。") elif hours_overdue < 16: # 中度:spawn 庞统介入 await spawn_agent("pangtong-fujunshi", f"流程卡住: Mail {mail.id} '{mail.title}' 超时 {hours_overdue:.0f} 小时未回复。请介入协调。") else: # 严重:创建 Issue + 通知庞统 await create_issue(title=f"流程严重超时: {mail.title}", labels=["blocked", "priority:high"]) await send_mail(to="pangtong-fujunshi", title=f"严重超时: {mail.title},已创建 Issue", ...) ``` **失败处置原则**: - 所有失败 → Issue 走正式流程,不私下通知 Agent 悄悄解决 - CI 失败 → CI workflow 写 PR 评论 → Webhook → Mail 通知 → Agent 修 → 走标准 PR 流程 - 部署失败回滚 → CI workflow 创建 Issue(priority:high) → 走标准 Bug 修复流程 - 超时未响应 → 三级处置(提醒→庞统介入→Issue+通知主公) **断点续传**: - 每个环节的状态都在 Gitea 上(PR 状态、CI 结果、Review 状态) - Mail 线程提供完整的可追溯记录 - 回复驱动确保正常流程自动推进,超时检测确保异常被捕获 - 流程卡住时,庞统可以根据 Mail 线程 + Gitea 状态快速定位断点并继续 ### §15.5 Mail 模板(流程强约束固化) > **注意**:Mail 模板里固化的是**流程强约束**——这个工作链特有的一步步怎么做。 > 共通技能(git 操作、审查清单等)放在 Skill 里(见 §10)。 **模板 1:任务指派(庞统/daemon → 开发者)** ``` Title: 任务指派: Issue #{N} - {标题} Text: Issue: {url} 分支: {branch_name} 风险级别: {level} 验收标准: {criteria} 流程: 1. 创建分支 {branch_name} 2. 编码 + 写 UT 3. push → 等 CI(CI 会自动跑) 4. CI 通过后创建 PR(Gitea API: POST /repos/{owner}/{repo}/pulls) 5. 等 Review(司马懿会自动收到通知) 6. Review 通过后 merge PR 如果 CI 失败:修复后重新 push,回到步骤 3 如果 Review 不通过:按意见修改后重新 push,回到步骤 3 完成后回复此 Mail 确认。 时限:{deadline} ``` **模板 2:Review 请求(Webhook → 司马懿)** ``` Title: Review 请求: PR #{N} Text: PR: {url} 标题: {title} 风险级别: {level} 改动文件: {file_list} 流程: 1. 读取 PR diff(Gitea API: GET /repos/{owner}/{repo}/pulls/{N}.diff) 2. 按审查清单审查(参考 code-review Skill) 3. 提交 Review(Gitea API: POST /repos/{owner}/{repo}/pulls/{N}/reviews) - APPROVE 或 REQUEST_CHANGES 4. 提交后张飞会自动收到通知 完成后回复此 Mail 确认。 时限:{deadline} ``` **模板 3:Review 结果通知(Webhook → 张飞)** ``` Title: Review {result}: PR #{N} Text: PR: {url} 结果: {APPROVED / REQUEST_CHANGES} 审查意见: {review_body} {如果通过}: 流程:merge PR(Gitea API: POST /repos/{owner}/{repo}/pulls/{N}/merge) {如果不通过}: 流程: 1. 按审查意见修改代码 2. push → CI 自动跑 3. CI 通过后等重新 Review 完成后回复此 Mail 确认。 ``` **模板 4:CI 失败通知(Webhook from issue_comment → 张飞)** ``` Title: CI 失败: PR #{N} Text: PR: {url} 失败测试: {failed_tests} 错误摘要: {error_summary} 流程: 1. 查看完整 CI 日志(PR 页面) 2. 修复失败的测试 3. push → CI 自动重跑 完成后回复此 Mail 确认。 ``` **模板 5:部署失败通知(→ 庞统,复杂事件 spawn)** ``` Title: 部署失败已回滚: {repo} Text: 仓库: {repo} 触发 commit: {sha} 失败原因: {error} 已自动回滚到: {previous_version} 已自动创建 Issue #{M}。 请协调排查。 ``` **模板 6:Bug 确认通知(司马懿 → 改动者)** ``` Title: Bug 确认: Issue #{N} - {标题} Text: Issue: {url} 根因: {根因描述} 复现步骤: {steps} 影响范围: {scope} 风险级别: {level} 分支: fix/issue-{N}-{简述} 流程: 1. 创建分支 fix/issue-{N}-{简述} 2. 修复 bug + 写回归测试 3. push → CI 自动跑 4. CI 通过后创建 PR 5. 等 Review 完成后回复此 Mail 确认。 时限:{deadline} ``` ### §15.6 Skill vs Mail 边界 | 维度 | Mail 模板 | Skill | |------|----------|-------| | 作用域 | 工具链流程特有 | 全局,所有项目通用 | | 强制度 | 强约束,Agent 必须按流程走 | 按需加载,提升质量 | | 内容 | 流程步骤+Gitea API 调用指令 | 共通技能(审查清单、git规范等) | | 示例 | "CI失败→修→push→等CI→等Review" | "怎么写好 UT"、"审查清单" | | 没有 Skill 能否运转 | ✅ 能(流程不会断) | 只是质量没那么高 | **原则:没有 Skill,流程还能运转。有了 Skill,流程运转得更好。** Skill 只放共通的、所有项目都能用的技能: - `git-workflow`:分支命名、commit 规范(所有项目通用) - `code-review`:审查清单(所有项目通用) - `testing-workflow`:测试规范(所有项目通用) - `bugfix-workflow`:根因定位方法(所有项目通用) 工具链特有的流程("CI 失败后怎么做"、"Review 通过后怎么做")全部固化在 Mail 模板里。 ### §15.7 Agent ID ↔ Git 用户名映射 CI workflow 和 Webhook 中的用户标识是 Git 用户名,Mail API 需要 Agent ID: | Git 用户名 | Agent ID | |-----------|----------| | zhangfei | zhangfei-dev | | jiangwei | jiangwei-infra | | simayi | simayi-challenger | | pangtong | pangtong-fujunshi | | guanyu | guanyu-dev | | zhaoyun | zhaoyun-data | daemon Webhook 模块中维护此映射表。