auto-sync: 2026-06-07 11:16:03
This commit is contained in:
@@ -1474,3 +1474,545 @@ CI workflow 和 Webhook 中的用户标识是 Git 用户名,Mail API 需要 Ag
|
||||
| zhaoyun | zhaoyun-data |
|
||||
|
||||
daemon Webhook 模块中维护此映射表。
|
||||
|
||||
|
||||
---
|
||||
|
||||
## §16. 事件中枢详细设计
|
||||
|
||||
> §16 是对 §15 串联架构的落地设计补充,定义事件中枢的具体实现方案。
|
||||
> 版本: v1.0-draft | 日期: 2026-06-07 | 状态: 待评审
|
||||
|
||||
## §16.0. 讨论纪要
|
||||
|
||||
本节记录设计过程中的关键讨论,供未来回溯。
|
||||
|
||||
### 两条线的定位(主公决策)
|
||||
|
||||
| 线 | 方向 | 机制 | 定位 |
|
||||
|----|------|------|------|
|
||||
| **出线** | Agent → Gitea | Agent 直接操作 Gitea,完成后发 Mail 通知下一个 Agent | Gitea = 黑板,Mail = 触发器 |
|
||||
| **入线** | 外部 → Agent | 外部事件(CI/部署/Webhook)→ 事件中枢 → Mail → Agent | 事件中枢 = 入口 |
|
||||
|
||||
**原则 1**:Agent 之间的协作不走事件中枢。中枢只处理"外部 → Agent"。
|
||||
**原则 2**:所有工具链留痕在 Gitea,Mail 是辅助推送。即使 Mail 失败,Agent 可主动查 Gitea 恢复上下文。
|
||||
**原则 3**:工具链反馈 Agent 的通知统一走事件中枢,避免散乱。
|
||||
|
||||
### 关键决策记录
|
||||
|
||||
| # | 决策 | 理由 |
|
||||
|---|------|------|
|
||||
| D1 | 不做第三种 task 类型 | 中枢产出就是 Mail(from=system, type=inform),模板填充 description,投递复用 spawner。区别只在内容(模板化)和元数据(结构化),不需要新的数据结构 |
|
||||
| D2 | 提示词独立模板文件 | 模板和代码分离,改文案不改代码,可审查可扩展 |
|
||||
| D3 | 中枢是 daemon 内模块 | 要访问 Blackboard 创建 Task,共享进程。用独立路由模块(`toolchain_routes.py`)保持职责清晰 |
|
||||
| D4 | 同步处理 | 事件处理很轻(解析+模板填充+创建Task),远在 Gitea 5秒超时内。复杂事件未来用 asyncio.create_task |
|
||||
| D5 | Agent ID = Gitea 用户名 | 设计目标一致,代码里留 `to_agent_id()` 函数兜底,实际直用。待姜维确认各 Agent 在 Gitea 上的注册用户名 |
|
||||
| D6 | CI/部署通知也走事件中枢 | 统一入口,不走 workflow 直接调 Mail API。CI workflow 写 PR comment → Gitea 触发 issue_comment Webhook → 中枢处理 |
|
||||
|
||||
---
|
||||
|
||||
## §16.1. 定位与边界
|
||||
|
||||
### 1.1 是什么
|
||||
|
||||
事件中枢是 daemon 内的一个路由模块,负责将**外部工具链事件**翻译成 Mail 通知推送给 Agent。
|
||||
|
||||
### 1.2 不是什么
|
||||
|
||||
- 不是消息队列
|
||||
- 不是 Agent 间通信通道(Agent 间协作走 Mail,不经过中枢)
|
||||
- 不是编排引擎(任务编排由 dispatcher + spawner 负责)
|
||||
|
||||
### 1.3 两条线
|
||||
|
||||
```
|
||||
出线(Agent → 工具链):
|
||||
Agent 直接操作 Gitea(创建 Issue/PR/Review 等)
|
||||
→ 完成后发 Mail 通知下一个 Agent
|
||||
→ 下一个 Agent 去读 Gitea 继续干活
|
||||
|
||||
入线(工具链 → Agent):
|
||||
外部事件(CI 结果/部署结果/Webhook 事件)
|
||||
→ 事件中枢
|
||||
→ 模板化 Mail
|
||||
→ Agent 收到通知,去 Gitea 查看详情并行动
|
||||
```
|
||||
|
||||
### 1.4 数据流
|
||||
|
||||
```
|
||||
外部事件源 事件中枢 Agent
|
||||
───────── ────── ──────
|
||||
|
||||
Gitea Webhook ─────┐
|
||||
│
|
||||
CI workflow ───────┤ toolchain_routes.py Mail Task
|
||||
(PR comment) ────┤ ┌─────────────────┐ (from: system)
|
||||
├──→│ 1. 接收事件 │ │
|
||||
Deploy workflow ──┤ │ 2. 验签/过滤 │ ↓
|
||||
(PR comment) ────┤ │ 3. 幂等检查 │ dispatcher
|
||||
│ │ 4. 选模板+填充 │ │
|
||||
daemon 内部 ───────┘ │ 5. 创建 Mail │ ↓
|
||||
(预留接口) └─────────────────┘ spawner 投递
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## §16.2. 事件分类与处理
|
||||
|
||||
### 2.1 事件来源
|
||||
|
||||
| 来源 | 触发方式 | 事件类型 |
|
||||
|------|---------|---------|
|
||||
| Gitea Webhook | Gitea 主动 POST | PR opened, Review submitted, Issue assigned, issue_comment |
|
||||
| CI workflow | CI 写 PR comment → 触发 issue_comment Webhook | CI 失败 |
|
||||
| Deploy workflow | Deploy 写 PR comment → 触发 issue_comment Webhook | 部署成功/失败 |
|
||||
| daemon 内部 | 内部函数调用 | 预留,当前不走中枢 |
|
||||
|
||||
### 2.2 事件处理矩阵
|
||||
|
||||
| 事件 | 来源 | 通知谁 | 模板 | 关键信息 |
|
||||
|------|------|--------|------|---------|
|
||||
| `pull_request` opened | Gitea Webhook | 司马懿(Review) | `review_request.md` | PR号、标题、作者、分支、文件列表、风险级别 |
|
||||
| `pull_request_review` submitted | Gitea Webhook | PR 作者 | `review_result.md` | PR号、审查结论、评论、审查者 |
|
||||
| `issues` assigned | Gitea Webhook | 被指派人 | `issue_assigned.md` | Issue号、标题、标签、描述、分支名建议 |
|
||||
| `issue_comment` (CI失败) | CI workflow → Webhook | PR 作者 | `ci_failure.md` | PR号、分支、失败步骤、错误摘要 |
|
||||
| `issue_comment` (部署成功) | Deploy workflow → Webhook | 庞统 | `deploy_success.md` | 仓库、版本、commit |
|
||||
| `issue_comment` (部署失败) | Deploy workflow → Webhook | 庞统 + 姜维 | `deploy_failure.md` | 仓库、失败原因、已回滚版本 |
|
||||
|
||||
### 2.3 事件过滤规则
|
||||
|
||||
不是所有事件都需要处理:
|
||||
|
||||
| 规则 | 说明 |
|
||||
|------|------|
|
||||
| 只处理白名单内的事件类型 | 未知的忽略 + 日志 |
|
||||
| issue_comment 需判断来源 | 只处理 CI/deploy workflow 写的评论(按特定前缀匹配,如 `[CI]`、`[Deploy]`) |
|
||||
| PR 作者/审查者必须是已知 Agent | 未知的忽略 + 日志 |
|
||||
| 幂等:同一事件不重复创建 Mail | 按 `{event_type}-{payload_id}` 去重 |
|
||||
|
||||
---
|
||||
|
||||
## §16.3. 模板系统
|
||||
|
||||
### 3.1 模板文件组织
|
||||
|
||||
```
|
||||
templates/toolchain/
|
||||
├── review_request.md # PR opened → 司马懿 Review
|
||||
├── review_result.md # Review submitted → PR 作者
|
||||
├── issue_assigned.md # Issue assigned → 开发者
|
||||
├── ci_failure.md # CI 失败 → PR 作者
|
||||
├── deploy_success.md # 部署成功 → 庞统
|
||||
└── deploy_failure.md # 部署失败 → 庞统+姜维
|
||||
```
|
||||
|
||||
### 3.2 模板格式
|
||||
|
||||
模板使用 `{variable}` 占位符,中枢填充后生成 Mail description。
|
||||
|
||||
**示例:`review_request.md`**
|
||||
|
||||
```markdown
|
||||
PR Review 请求
|
||||
|
||||
PR: http://192.168.2.154:3000/{repo}/pulls/{pr_number}
|
||||
标题: {pr_title}
|
||||
作者: {pr_author}
|
||||
分支: {branch}
|
||||
风险级别: {risk_level}
|
||||
改动文件:
|
||||
{file_list}
|
||||
|
||||
流程:
|
||||
1. 读取 PR diff(Gitea API: GET /repos/{repo_owner}/{repo}/pulls/{pr_number}.diff)
|
||||
2. 按审查清单审查(参考 code-review Skill)
|
||||
3. 提交 Review(Gitea API: POST /repos/{repo_owner}/{repo}/pulls/{pr_number}/reviews)
|
||||
4. 提交后改动者会自动收到通知
|
||||
|
||||
完成后回复此 Mail 确认。
|
||||
```
|
||||
|
||||
### 3.3 模板变量提取
|
||||
|
||||
| 变量 | 来源 | 提取方式 |
|
||||
|------|------|---------|
|
||||
| `pr_number` | Webhook payload | `event["pull_request"]["number"]` |
|
||||
| `pr_title` | Webhook payload | `event["pull_request"]["title"]` |
|
||||
| `pr_author` | Webhook payload | `to_agent_id(event["pull_request"]["user"]["login"])` |
|
||||
| `branch` | Webhook payload | `event["pull_request"]["head"]["ref"]` |
|
||||
| `file_list` | Webhook payload | `event["pull_request"]["changed_files"]` 或需要额外 API 调用 |
|
||||
| `risk_level` | daemon 计算 | 按文件路径规则匹配(见 §3.4) |
|
||||
| `repo` | Webhook payload | 从 `event["repository"]["full_name"]` 提取 |
|
||||
|
||||
### 3.4 风险级别自动判定(简化版)
|
||||
|
||||
按改动文件路径匹配规则:
|
||||
|
||||
```python
|
||||
HIGH_PATTERNS = ["**/spawner*", "**/ticker*", "**/dispatcher*",
|
||||
"**/router*", "**/guardrails*", "**/strategy*", "**/risk*"]
|
||||
|
||||
def calc_risk_level(changed_files: list[str]) -> str:
|
||||
for f in changed_files:
|
||||
for pattern in HIGH_PATTERNS:
|
||||
if fnmatch(f, pattern):
|
||||
return "high"
|
||||
return "standard"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## §16.4. 技术设计
|
||||
|
||||
### 4.1 模块结构
|
||||
|
||||
```
|
||||
src/api/
|
||||
├── toolchain_routes.py # 事件中枢路由(~150行)
|
||||
├── mail_routes.py # 现有 Mail API
|
||||
└── ...
|
||||
|
||||
src/daemon/
|
||||
├── toolchain_templates.py # 模板加载+填充(~80行)
|
||||
├── mail_notify.py # 现有 Mail 失败通知
|
||||
└── ...
|
||||
|
||||
templates/toolchain/
|
||||
├── review_request.md
|
||||
├── review_result.md
|
||||
├── issue_assigned.md
|
||||
├── ci_failure.md
|
||||
├── deploy_success.md
|
||||
└── deploy_failure.md
|
||||
```
|
||||
|
||||
### 4.2 toolchain_routes.py 接口设计
|
||||
|
||||
```python
|
||||
# src/api/toolchain_routes.py
|
||||
|
||||
from fastapi import APIRouter, Request, Header, HTTPException
|
||||
from src.daemon.toolchain_templates import TemplateEngine
|
||||
|
||||
router = APIRouter()
|
||||
engine = TemplateEngine()
|
||||
|
||||
GITEA_WEBHOOK_SECRET = os.environ.get("GITEA_WEBHOOK_SECRET", "")
|
||||
|
||||
@router.post("/webhook/gitea")
|
||||
async def handle_gitea_webhook(
|
||||
request: Request,
|
||||
x_gitea_event: str = Header(...),
|
||||
x_gitea_signature: str = Header(None),
|
||||
x_gitea_delivery: str = Header(None),
|
||||
):
|
||||
"""接收 Gitea Webhook,翻译成 Mail"""
|
||||
|
||||
body = await request.body()
|
||||
|
||||
# 1. 签名验证(可选)
|
||||
if GITEA_WEBHOOK_SECRET:
|
||||
expected = hmac.new(GITEA_WEBHOOK_SECRET.encode(), body, sha256).hexdigest()
|
||||
if not hmac.compare_digest(expected, (x_gitea_signature or "")):
|
||||
raise HTTPException(403, "Invalid signature")
|
||||
|
||||
event = json.loads(body)
|
||||
|
||||
# 2. 幂等检查
|
||||
event_key = f"{x_gitea_event}-{x_gitea_delivery}"
|
||||
if is_duplicate(event_key):
|
||||
return {"status": "duplicate"}
|
||||
|
||||
# 3. 路由到对应处理器
|
||||
handler = HANDLERS.get(x_gitea_event)
|
||||
if not handler:
|
||||
logger.info("Ignoring unhandled event: %s", x_gitea_event)
|
||||
return {"status": "ignored"}
|
||||
|
||||
# 4. 处理事件 → 创建 Mail
|
||||
try:
|
||||
result = await handler(engine, event)
|
||||
return {"status": "ok", "mail_id": result}
|
||||
except Exception as e:
|
||||
logger.exception("Failed to handle %s event", x_gitea_event)
|
||||
raise HTTPException(500, str(e))
|
||||
```
|
||||
|
||||
### 4.3 事件处理器
|
||||
|
||||
每个事件类型一个处理函数,职责:解析 payload → 选模板 → 填充 → 创建 Mail Task。
|
||||
|
||||
```python
|
||||
async def handle_pr_opened(engine: TemplateEngine, event: dict) -> str:
|
||||
"""PR opened → Review 请求给司马懿"""
|
||||
pr = event["pull_request"]
|
||||
|
||||
# 提取变量
|
||||
variables = {
|
||||
"pr_number": pr["number"],
|
||||
"pr_title": pr["title"],
|
||||
"pr_author": to_agent_id(pr["user"]["login"]),
|
||||
"branch": pr["head"]["ref"],
|
||||
"repo": event["repository"]["full_name"],
|
||||
"repo_owner": event["repository"]["owner"]["login"],
|
||||
"risk_level": calc_risk_level(get_changed_files(pr)),
|
||||
"file_list": format_file_list(get_changed_files(pr)),
|
||||
}
|
||||
|
||||
# 填充模板
|
||||
text = engine.render("review_request.md", variables)
|
||||
|
||||
# 创建 Mail Task
|
||||
meta = {
|
||||
"source": "toolchain",
|
||||
"webhook_event": "pull_request_opened",
|
||||
"pr_number": pr["number"],
|
||||
"repo": variables["repo"],
|
||||
}
|
||||
|
||||
return create_mail_task(
|
||||
to="simayi-challenger",
|
||||
title=f"Review 请求: PR #{pr['number']} {pr['title']}",
|
||||
text=text,
|
||||
meta=meta,
|
||||
)
|
||||
|
||||
|
||||
async def handle_review_submitted(engine: TemplateEngine, event: dict) -> str:
|
||||
"""Review submitted → 结果通知 PR 作者"""
|
||||
review = event["review"]
|
||||
pr = event["pull_request"]
|
||||
pr_author = to_agent_id(pr["user"]["login"])
|
||||
state = review["state"] # APPROVED / REQUEST_CHANGES / COMMENTED
|
||||
|
||||
if state == "COMMENTED":
|
||||
return None # 普通评论不通知
|
||||
|
||||
variables = {
|
||||
"pr_number": pr["number"],
|
||||
"pr_title": pr["title"],
|
||||
"result": "通过" if state == "APPROVED" else "不通过",
|
||||
"reviewer": to_agent_id(review["user"]["login"]),
|
||||
"review_body": review["body"] or "无",
|
||||
"repo": event["repository"]["full_name"],
|
||||
"repo_owner": event["repository"]["owner"]["login"],
|
||||
}
|
||||
|
||||
template = "review_result.md"
|
||||
text = engine.render(template, variables)
|
||||
|
||||
return create_mail_task(
|
||||
to=pr_author,
|
||||
title=f"Review {variables['result']}: PR #{pr['number']}",
|
||||
text=text,
|
||||
meta={"source": "toolchain", "webhook_event": "review_submitted", "pr_number": pr["number"]},
|
||||
)
|
||||
|
||||
|
||||
async def handle_issue_comment(engine: TemplateEngine, event: dict) -> str:
|
||||
"""issue_comment → 判断来源,路由到 CI/部署通知"""
|
||||
comment_body = event["comment"]["body"]
|
||||
|
||||
if comment_body.startswith("[CI]"):
|
||||
return await handle_ci_comment(engine, event)
|
||||
elif comment_body.startswith("[Deploy]"):
|
||||
return await handle_deploy_comment(engine, event)
|
||||
|
||||
return None # 非 CI/部署评论不处理
|
||||
|
||||
|
||||
# HANDLERS 注册表
|
||||
HANDLERS = {
|
||||
"pull_request": handle_pr_event, # 根据 action 分发
|
||||
"pull_request_review": handle_review_submitted,
|
||||
"issues": handle_issue_event, # 根据 action 分发
|
||||
"issue_comment": handle_issue_comment,
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 共用函数
|
||||
|
||||
```python
|
||||
def to_agent_id(gitea_username: str) -> str:
|
||||
"""Gitea 用户名 → Agent ID。当前设计目标一致,直用。"""
|
||||
return gitea_username
|
||||
|
||||
def create_mail_task(to: str, title: str, text: str, meta: dict) -> str:
|
||||
"""创建 Mail Task(from=system, type=inform)
|
||||
复用 mail_notify.py 的模式:直接通过 Blackboard 创建 Task。
|
||||
"""
|
||||
# 从 mail_routes.py 提取共用逻辑,或直接复用 mail_notify 的方式
|
||||
...
|
||||
|
||||
def is_duplicate(event_key: str) -> bool:
|
||||
"""幂等检查:同一事件不重复创建 Mail"""
|
||||
...
|
||||
|
||||
def calc_risk_level(files: list[str]) -> str:
|
||||
"""按文件路径规则判定风险级别"""
|
||||
...
|
||||
|
||||
def get_changed_files(pr: dict) -> list[str]:
|
||||
"""从 PR payload 提取改动文件列表"""
|
||||
...
|
||||
```
|
||||
|
||||
### 4.5 模板引擎
|
||||
|
||||
```python
|
||||
# src/daemon/toolchain_templates.py
|
||||
|
||||
from pathlib import Path
|
||||
import string
|
||||
|
||||
TEMPLATE_DIR = Path(__file__).parent.parent.parent / "templates" / "toolchain"
|
||||
|
||||
class TemplateEngine:
|
||||
def __init__(self, template_dir: Path = TEMPLATE_DIR):
|
||||
self.template_dir = template_dir
|
||||
self._cache = {}
|
||||
|
||||
def render(self, template_name: str, variables: dict) -> str:
|
||||
"""加载模板文件并填充变量"""
|
||||
if template_name not in self._cache:
|
||||
path = self.template_dir / template_name
|
||||
self._cache[template_name] = path.read_text()
|
||||
|
||||
template = self._cache[template_name]
|
||||
return template.format_map(defaultdict(str, variables))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## §16.5. 错误处理
|
||||
|
||||
| 场景 | 处理 | HTTP 返回 |
|
||||
|------|------|----------|
|
||||
| 签名验证失败 | 日志 warning | 403 |
|
||||
| payload 解析失败 | 日志 error | 200(不触发 Gitea 重试) |
|
||||
| 未知事件类型 | 忽略 + 日志 info | 200 |
|
||||
| 幂等检测到重复 | 忽略 + 日志 info | 200 |
|
||||
| 未知 Agent(不在映射表) | 忽略 + 日志 warning | 200 |
|
||||
| 模板填充失败 | 日志 error | 500(触发 Gitea 重试) |
|
||||
| Mail 创建失败 | 日志 error | 500(触发 Gitea 重试) |
|
||||
|
||||
**原则**:
|
||||
- daemon 自身能处理的错误(格式、过滤、幂等)→ 返回 200,不让 Gitea 无意义重试
|
||||
- daemon 处理不了的错误(数据库、内部异常)→ 返回 500,让 Gitea 重试
|
||||
|
||||
---
|
||||
|
||||
## §16.6. CI/Deploy Workflow 配合
|
||||
|
||||
### 6.1 CI 失败通知
|
||||
|
||||
CI workflow 失败时写 PR comment,触发 issue_comment Webhook:
|
||||
|
||||
```yaml
|
||||
# .gitea/workflows/ci.yml
|
||||
- name: Report failure
|
||||
if: failure()
|
||||
run: |
|
||||
curl -s -X POST \
|
||||
"http://192.168.2.154:3000/api/v1/repos/{owner}/{repo}/issues/{pr_number}/comments" \
|
||||
-H "Authorization: token ${{ secrets.CI_TOKEN }}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"body\": \"[CI] CI 失败\\n\\n分支: ${{ gitea.ref_name }}\\n失败步骤: ${{ job.status }}\\n错误摘要: $(tail -20 $GITHUB_STEP_SUMMARY)\"
|
||||
}"
|
||||
```
|
||||
|
||||
### 6.2 Deploy 结果通知
|
||||
|
||||
同理,deploy workflow 成功/失败时写 comment:
|
||||
|
||||
```yaml
|
||||
# .gitea/workflows/deploy.yml
|
||||
- name: Report success
|
||||
if: success()
|
||||
run: |
|
||||
curl -s -X POST \
|
||||
"http://192.168.2.154:3000/api/v1/repos/{owner}/{repo}/issues/{pr_number}/comments" \
|
||||
-H "Authorization: token ${{ secrets.CI_TOKEN }}" \
|
||||
-d "{\"body\": \"[Deploy:成功] 版本: $(bash scripts/deploy.sh --version)\\n请确认后关闭 Issue.\"}"
|
||||
|
||||
- name: Report failure
|
||||
if: failure()
|
||||
run: |
|
||||
curl -s -X POST \
|
||||
"http://192.168.2.154:3000/api/v1/repos/{owner}/{repo}/issues/{pr_number}/comments" \
|
||||
-H "Authorization: token ${{ secrets.CI_TOKEN }}" \
|
||||
-d "{\"body\": \"[Deploy:失败] 已回滚到上一版本。原因: ...\"}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## §16.7. 配置
|
||||
|
||||
| 环境变量 | 用途 | 默认值 |
|
||||
|---------|------|--------|
|
||||
| `GITEA_WEBHOOK_SECRET` | Webhook HMAC 签名密钥(可选) | 空(跳过验签) |
|
||||
| `BLACKBOARD_ROOT` | Blackboard 数据根目录(已有) | `~/.sanguo_projects/sanguo_moziplus_v2/data` |
|
||||
| `TOOLCHAIN_TEMPLATES_DIR` | 模板文件目录(可选) | `templates/toolchain/` |
|
||||
|
||||
---
|
||||
|
||||
## §16.8. 待确认项
|
||||
|
||||
| # | 项 | 负责人 | 说明 |
|
||||
|---|------|--------|------|
|
||||
| 1 | 各 Agent 在 Gitea 上的注册用户名是否和 Agent ID 一致 | 姜维 | 决定是否需要映射表 |
|
||||
| 2 | Gitea Webhook 是否已配置 secret | 姜维 | 当前已配未启用 |
|
||||
| 3 | CI workflow 是否已有写 PR comment 的 step | — | 当前 CI workflow 可能没有 |
|
||||
| 4 | `from=system` 走 HTTP API 还是只走内部函数 | — | mail_routes.py 当前只在内部函数支持 system |
|
||||
| 5 | PR changed_files 是否包含在 Webhook payload 中 | — | Gitea v1.23.4 可能需要额外 API 调用 |
|
||||
|
||||
---
|
||||
|
||||
## §16.9. 实施计划
|
||||
|
||||
| 步骤 | 内容 | 依赖 |
|
||||
|------|------|------|
|
||||
| 1 | `toolchain_routes.py` 骨架 + Gitea Webhook 接收 + 签名验证 | 无 |
|
||||
| 2 | `toolchain_templates.py` 模板引擎 | 无 |
|
||||
| 3 | 6 个模板文件 | 步骤 2 |
|
||||
| 4 | 4 个事件处理器(PR/Review/Issue/Comment) | 步骤 1+3 |
|
||||
| 5 | 幂等检查(内存缓存或 SQLite 记录) | 步骤 1 |
|
||||
| 6 | `create_mail_task` 共用函数(从 mail_routes.py 提取) | 无 |
|
||||
| 7 | CI/Deploy workflow 加 comment step | 步骤 1+4 |
|
||||
| 8 | Gitea Webhook 启用 + 测试 | 姜维 |
|
||||
| 9 | 端到端测试 | 步骤 1-8 |
|
||||
|
||||
### 9.1 改动量估算
|
||||
|
||||
| 文件 | 行数 | 类型 |
|
||||
|------|------|------|
|
||||
| `src/api/toolchain_routes.py` | ~200 | 新增 |
|
||||
| `src/daemon/toolchain_templates.py` | ~60 | 新增 |
|
||||
| `templates/toolchain/*.md` | ~200(6个文件) | 新增 |
|
||||
| `src/api/mail_routes.py` | ~20 | 修改(提取共用函数) |
|
||||
| `.gitea/workflows/ci.yml` | ~15 | 修改(加 comment step) |
|
||||
| `.gitea/workflows/deploy.yml` | ~15 | 修改(加 comment step) |
|
||||
| **总计** | **~510** | |
|
||||
|
||||
---
|
||||
|
||||
## §16.10. 评审检查清单
|
||||
|
||||
- [ ] §0 讨论纪要是否准确反映了决策过程
|
||||
- [ ] §1 两条线的边界是否清晰(出线不走中枢,入线统一走中枢)
|
||||
- [ ] §2 事件矩阵是否有遗漏
|
||||
- [ ] §3 模板内容是否完整,变量提取是否正确
|
||||
- [ ] §4 接口设计是否合理,共用函数提取是否恰当
|
||||
- [ ] §5 错误处理策略是否完备
|
||||
- [ ] §6 CI/Deploy workflow 配合方案是否可行
|
||||
- [ ] §8 待确认项是否完整
|
||||
- [ ] §9 实施步骤是否合理
|
||||
|
||||
|
||||
### v2.0 → v2.1 变更(事件中枢落地设计)
|
||||
|
||||
| 编号 | 变更内容 |
|
||||
|------|---------|
|
||||
| §16 | 新增事件中枢详细设计(§16.0-§16.10),基于 §15 串联架构 v2.0 的落地细节 |
|
||||
|
||||
Reference in New Issue
Block a user