Compare commits

...

23 Commits

Author SHA1 Message Date
cfdaily f4fea8f418 [moz] fix(ci): pip install 加 no_proxy=* 绕过系统代理白名单
CI / lint (pull_request) Successful in 18s
CI / test (pull_request) Successful in 13m40s
CI / frontend (pull_request) Successful in 15s
CI / notify-on-failure (pull_request) Successful in 0s
CI runner 继承了系统 Wi-Fi 代理(127.0.0.1:7890),代理是白名单机制,
pip install 走代理被拒绝。加 env no_proxy=* 让 pip 直连。
2026-06-20 07:44:37 +08:00
cfdaily 3a11327113 [moz] docs(§20): v2.2 纳入姜维 v2.0 Review S3(must_haves 改名影响面)
CI / lint (pull_request) Failing after 50s
CI / test (pull_request) Has been skipped
CI / frontend (pull_request) Has been skipped
CI / notify-on-failure (pull_request) Successful in 2s
2026-06-20 00:45:31 +08:00
cfdaily ddc5eb9897 [moz] docs(§20): v2.1 fix M1 dispatcher 直接SQL声明 + M2 Phase格式 + S1/S2 TaskAdapter残留清理
CI / lint (pull_request) Successful in 17s
CI / test (pull_request) Successful in 4m44s
CI / frontend (pull_request) Successful in 14s
CI / notify-on-failure (pull_request) Successful in 0s
2026-06-20 00:43:49 +08:00
cfdaily b0f4572ba6 [moz] docs(§20): v2.0 修订——Repository 模式换底 + Review 反馈整合
CI / lint (pull_request) Successful in 30s
CI / test (pull_request) Successful in 8m30s
CI / frontend (pull_request) Successful in 19s
CI / notify-on-failure (pull_request) Successful in 0s
庞统修正:
- 砍掉 task_index + TaskAdapter,改为 Repository 模式(Queries 类内部换底)
- 协作数据从 Gitea API 读,执行数据从 task_state 表读

司马懿 Review S1-S4 + G2:
- S1: 表数量 12→14 修正
- S2: P4 补充 action_report 识别方案(body 标记约定)
- S3: PR merge 关 Issue 需要 Closes #N commit message 约定
- S4: CI status webhook 验证放到 Phase 0
- G2: Mail 剩余职责明确

姜维 Review:
- task_state 加 issue_updated_at 缓存失效判断
- must_haves 改名 daemon_meta
2026-06-20 00:40:04 +08:00
cfdaily b6e58a164c docs(§20): 纳入姜维 Review 反馈 v1.1
CI / lint (pull_request) Successful in 13s
CI / test (pull_request) Successful in 28s
CI / frontend (pull_request) Successful in 12s
CI / notify-on-failure (pull_request) Successful in 0s
- task_index 加 issue_updated_at + issue_body_cache 字段
- must_haves 改名 daemon_meta(避免概念混淆)
- P2 推荐 TaskAdapter 替代 lazy load
- P4 补充 mention 解析适配层说明
- 新增 Phase 0 前置(webhook 权限)
- Phase 1 加 CI status webhook 验证
- 风险表补充 CI status 不触发 + 权限不足两项
2026-06-19 21:21:46 +08:00
cfdaily ea04b4c483 [moz] docs(§20): Issue-Centric Orchestration — Gitea Issue 替代黑板 DB 协作面
CI / lint (pull_request) Successful in 12s
CI / test (pull_request) Successful in 28s
CI / frontend (pull_request) Successful in 12s
CI / notify-on-failure (pull_request) Successful in 0s
设计目标:
1. 黑板 DB 协作面迁移到 Gitea Issue
2. 成果物以 Gitea 为基础(分支+PR)
3. webhook 部分替代 ticker
4. task 状态+spawner 逻辑不变
5. prompt 改造(黑板 API → Gitea API)

§3 目标架构:Gitea 做协作介质,daemon task_index 做轻量索引
§5 daemon 改造点:数据访问层(P1-P4)需讨论
§9 实施路径:5 个 Phase 分阶段实施
2026-06-19 21:05:17 +08:00
pangtong-fujunshi 04568108a6 Merge PR #95: [moz] impl(§17): issue_assigned steps git 操作具体化 + ToolchainApiSection Git 说明
Deploy / ci (push) Successful in 10s
Deploy / deploy (push) Successful in 11s
Deploy / notify-deploy-failure (push) Successful in 0s
Deploy / notify-deploy-success (push) Successful in 1s
2026-06-19 05:56:00 +00:00
cfdaily 6ea43d76e3 [moz] impl(§17): issue_assigned steps git 操作具体化 + ToolchainApiSection Git 说明
CI / lint (pull_request) Successful in 10s
CI / test (pull_request) Successful in 27s
CI / frontend (pull_request) Successful in 11s
CI / notify-on-failure (pull_request) Successful in 0s
改动 1: issue_assigned 编码路径 steps 改为具体 git 命令
  (checkout main → pull → checkout -b → add/commit → push)
改动 2: ToolchainApiSection 新增 Git 操作说明段落(含开发目录路径)
改动 3: 测试更新(issue_assigned 断言 + 3 个 Git 说明测试)
466 passed
2026-06-19 13:53:44 +08:00
pangtong-fujunshi 09520a414e Merge PR #94: [moz] docs(§17): issue_assigned steps git 操作具体化
Deploy / ci (push) Successful in 10s
Deploy / deploy (push) Successful in 11s
Deploy / notify-deploy-failure (push) Successful in 0s
Deploy / notify-deploy-success (push) Successful in 1s
2026-06-19 05:52:15 +00:00
cfdaily 9388f3ecc1 [moz] docs(§17): issue_assigned steps git 操作具体化 + ToolchainApiSection Git 说明段落
CI / lint (pull_request) Successful in 14s
CI / test (pull_request) Successful in 28s
CI / frontend (pull_request) Successful in 12s
CI / notify-on-failure (pull_request) Successful in 0s
§6.2 issue_assigned 编码路径 steps 改为具体 git 命令序列
  (checkout main → pull → checkout -b → commit → push)
§6.4 新增 Git 操作说明段落设计(ToolchainApiSection 通用 git 参考)
§6.1 对照表更新步数描述
设计原则:系统不做分支管理,agent 自己执行 git 操作
2026-06-19 13:49:33 +08:00
pangtong-fujunshi cdc49ac74d Merge PR #93: [moz] impl(§17): CI/部署失败 steps 分支指引 + 基础设施 Issue 转交流程
Deploy / ci (push) Successful in 10s
Deploy / deploy (push) Successful in 13s
Deploy / notify-deploy-failure (push) Successful in 0s
Deploy / notify-deploy-success (push) Successful in 1s
2026-06-19 05:20:36 +00:00
cfdaily f74ae30d41 [moz] impl(§17): CI/部署失败 steps 分支指引 + 基础设施 Issue 转交流程
CI / lint (pull_request) Successful in 10s
CI / test (pull_request) Successful in 27s
CI / frontend (pull_request) Successful in 13s
CI / notify-on-failure (pull_request) Successful in 0s
改动 1: ci_failure steps 增加分支指引(代码问题自己修/基础设施问题提Issue给姜维)
改动 2: deploy_failure steps 同上分支指引(2处定义都改)
改动 3: issue_assigned handler 按 type/infrastructure label 分流
  - infrastructure label → infrastructure_failure event_type(运维排查 steps)
  - 其他 → 原有编码 steps
改动 4: ToolchainApiSection 新增「需要创建 Issue 时」API 指引段落
改动 5: Red Flags 新增「不是我代码的问题」条目
测试: 8 个新测试,463 passed
2026-06-19 13:18:11 +08:00
pangtong-fujunshi 67b504c5db Merge PR #89: [moz] docs(§19): cron delivery mode 修正 none→announce
Deploy / ci (push) Successful in 9s
Deploy / deploy (push) Successful in 13s
Deploy / notify-deploy-failure (push) Successful in 1s
Deploy / notify-deploy-success (push) Successful in 1s
2026-06-19 05:07:40 +00:00
cfdaily 230b8c9cd9 chore: retrigger CI after ensurepip fix
CI / lint (pull_request) Successful in 9s
CI / test (pull_request) Successful in 28s
CI / frontend (pull_request) Successful in 10s
CI / notify-on-failure (pull_request) Successful in 0s
2026-06-19 09:48:52 +08:00
cfdaily 5b73319aaf [moz] docs(§19): fix M1 JSON 配置块 delivery.mode 同步改为 announce
司马懿 M1:3 处 JSON 配置块 delivery.mode 仍为 none,与设计要点文字不一致。
同步修正为 announce。
2026-06-19 09:48:52 +08:00
cfdaily 8c7c277167 [moz] docs(§19): cron delivery mode 修正 none→announce
根因:isolated session + delivery:none 导致 cron 执行后零可见性
修复:L1/L2/IMPROVE cron delivery 统一改为 announce
2026-06-19 09:48:52 +08:00
pangtong-fujunshi 999cd1cc10 Merge PR #90
Deploy / ci (push) Successful in 8s
Deploy / deploy (push) Successful in 10s
Deploy / notify-deploy-failure (push) Successful in 0s
Deploy / notify-deploy-success (push) Successful in 0s
2026-06-19 01:48:34 +00:00
cfdaily 0475e40529 [moz] docs(§17): fix M1 章节引用 §6.3→§6.4 + S1 label分流待实现标注 + S2 label预创建说明 + G1 错别字
CI / lint (pull_request) Successful in 10s
CI / test (pull_request) Successful in 28s
CI / frontend (pull_request) Successful in 11s
CI / notify-on-failure (pull_request) Successful in 0s
2026-06-19 09:48:13 +08:00
cfdaily ca9b750656 [moz] ci: trigger CI after /tmp cleanup (jiangwei check) 2026-06-19 09:48:13 +08:00
cfdaily 7e832ee865 [moz] docs(§17): CI/部署失败 steps 分支指引 + 基础设施 Issue 转交流程
§6.2 CI 失败 steps: 增加 a(代码问题)/b(基础设施问题) 分支
§6.2 部署失败 steps: 同上分支指引
§6.2 Issue 指派 steps: 按 type/infrastructure label 分流
§6.4 新增: 基础设施 Issue 转交流程
  - Issue 提在来源仓库
  - Issue body 结构化模板(问题描述+错误来源链接+日志+判断依据)
  - issue_assigned handler label 分流(运维 vs 编码)
  - ToolchainApiSection 新增 Issue 创建 API 指引
  - Red Flags 补充
§5.2: 补充首次 steps 分支指引说明,修正 §5.2.1~3 指向
2026-06-19 09:48:13 +08:00
jiangwei-infra 1c7be0e782 Merge PR #92: [moz] fix(ci): lint venv 残留导致 ensurepip 失败
Deploy / ci (push) Successful in 21s
Deploy / deploy (push) Successful in 12s
Deploy / notify-deploy-failure (push) Successful in 1s
Deploy / notify-deploy-success (push) Successful in 1s
2026-06-19 01:45:51 +00:00
cfdaily 49d0b3a789 [moz] fix(ci): lint venv 残留导致 ensurepip 失败
CI / lint (pull_request) Successful in 10s
CI / test (pull_request) Successful in 27s
CI / frontend (pull_request) Successful in 12s
CI / notify-on-failure (pull_request) Successful in 0s
根因:lint job 创建 /tmp/ci-venv-lint 后不清理,下次 CI 运行
时 python3 -m venv 在已有目录上 upgrade,ensurepip 调用
/tmp/ci-venv-lint/bin/python3 -Im ensurepip 失败(exit 1)。
test job 已有 rm -rf /tmp/ci-venv-test,lint job 缺失。

修复:lint Setup Python 首行加 rm -rf /tmp/ci-venv-lint。

验证:PR #90 分支临时修复后 CI run 406/407 全绿。

Closes #91
2026-06-19 09:36:56 +08:00
pangtong-fujunshi 5505ac9c5c Merge PR #88: S6 deprecated 代码标记 + ticker 经验蒸馏空转修复
Deploy / ci (push) Failing after 7s
Deploy / deploy (push) Has been skipped
Deploy / notify-deploy-failure (push) Successful in 2s
Deploy / notify-deploy-success (push) Successful in 0s
2026-06-18 15:07:26 +00:00
8 changed files with 694 additions and 52 deletions
+5
View File
@@ -25,7 +25,10 @@ jobs:
- uses: actions/checkout@v4
- name: Setup Python
env:
no_proxy: "*"
run: |
rm -rf /tmp/ci-venv-lint
python3 -m venv /tmp/ci-venv-lint
/tmp/ci-venv-lint/bin/pip install --quiet --upgrade pip
/tmp/ci-venv-lint/bin/pip install --quiet flake8
@@ -42,6 +45,8 @@ jobs:
- uses: actions/checkout@v4
- name: Setup Python
env:
no_proxy: "*"
run: |
rm -rf /tmp/ci-venv-test
python3 -m venv /tmp/ci-venv-test
+2
View File
@@ -22,6 +22,8 @@ jobs:
- uses: actions/checkout@v4
- name: Setup Python
env:
no_proxy: "*"
run: |
python3 -m venv /tmp/ci-venv-deploy
/tmp/ci-venv-deploy/bin/pip install --quiet flake8 fastapi pydantic pyyaml uvicorn requests pytest pytest-asyncio httpx
+121 -16
View File
@@ -391,7 +391,11 @@ def verify_completion(self, task_id: str, db_path: Path) -> VerifyResult:
#### 完整设计
三分路的详细伪代码、失败上限、决策依据见 §5.2.1~§5.2.3on_failure 分路处理详细设计)。
三分路的详细设计见 §6.4(基础设施 Issue 转交流程)和 toolchain_handler.py 实现(`_handle_infrastructure_failure` / `_classify_failure`)。
#### 首次 steps 分支指引
三分路是 verify 失败后的兜底机制。此外,ci_failure 和 deploy_failure 的首次 toolchain task steps 中**已包含分支指引**——agent 在执行过程中自行判断失败原因,如果是基础设施问题则直接创建 Issue 指派 jiangwei-infra(见 §6.4)。三分路作为第二道防线,覆盖 agent 未正确判断或未执行分支的情况。
### 5.3 action_report comment 格式
@@ -431,9 +435,9 @@ Agent 可能写了 action_report 但没真做。缓解机制:
| Review 请求 → reviewer | review_request | toolchain | 4 步 | 读 diff + 审查 + 提交 Review + report |
| Review 有新提交 → reviewer | review_updated | toolchain | 4 步 | 读 diff + 检查修改 + 提交 Review + report |
| Review 评论 → PR 作者 | review_comment | toolchain | 3 步 | 查看评论 + 响应(修改/回复)+ report |
| CI 失败 → PR 作者 | ci_failure | toolchain | 4 步 | 查 CI 日志 + 修测试 + push + report |
| Issue 指派 → 开发者 | issue_assigned | toolchain | 6 步 | 创建分支 + 编码 + push + CI + PR + report |
| 部署失败 → 运维 | deploy_failure | toolchain | 4 步 | 查日志 + 排查 + 修+重部署 + report |
| CI 失败 → PR 作者 | ci_failure | toolchain | 3 步 | 查 CI 日志 + 分支判断(代码问题自己修 / 基础设施问题提 Issue 给姜维)+ report |
| Issue 指派 → 开发者 | issue_assigned / infrastructure_failure | toolchain | 6 步(编码,含具体 git 命令)或 4 步(运维) | 按 label 分流:type/infrastructure → 运维排查;其他 → git checkout main/pull → 创建分支 编码 push CI PR + report |
| 部署失败 → 运维 | deploy_failure | toolchain | 3 步 | 查日志 + 分支判断(代码/配置问题自己修 / 基础设施问题提 Issue 给姜维)+ report |
| @mention → 被@者 | mention | toolchain | 按 guidance | 按 mention 模板的 response_guidance + report |
| PR 合并 → PR 作者 | review_merged | toolchain | 0 步 | 纯通知,走 _send_toolchain_tasksteps 为空,verify 始终通过) |
@@ -502,29 +506,46 @@ event_type: ci_failure
action_type: ci_failure
steps:
1. 查看完整 CI 日志(PR 页面或 Gitea Actions 页面)
2. 修复失败的测试
3. push → CI 自动重跑
4. 提交 action report
2. 根据 CI 日志判断失败原因类型:
a. 代码问题(lint/test 失败)→ 修复失败的测试 → push 到原分支 → CI 自动重跑
b. 基础设施问题(runner 环境/Python/venv/Gitea/网络故障)→ 在该仓库创建 Issue 指派 jiangwei-infra(见 §6.4),label 必须包含 type/infrastructure
3. 提交 action report — 报告中说明判断的原因类型和执行的操作
context:
pr_number, repo, branch, error_summary
```
**分支设计说明**:原设计假设"CI 失败 = 代码问题"steps 只有"修测试 + push"一条路径。实际运行中发现 CI 失败可能是 runner 环境故障(如 ensurepip 失败),agent 判断为基础设施问题后不知道该做什么。现在 steps 中明确两条分支,agent 自行判断后走对应路径。
#### Issue 指派 → 开发者
```
event_type: issue_assigned
action_type: issue_assigned
steps:
1. 创建分支 fix/{issue_number}-{brief}
event_type: issue_assigned 或 infrastructure_failure
action_type: issue_assigned 或 infrastructure_failure
steps(按 label 分流):
# 默认路径(编码任务):
1. 在开发目录执行 git 操作:
a. git checkout main && git pull origin main (确保从最新代码分叉)
b. git checkout -b fix/{issue_number}-{brief} (创建功能分支)
2. 编码 + 写 UT
3. push → 等 CI
4. CI 通过后创建 PRGitea API: POST /repos/{repo}/pulls
3. git add -A && git commit -m "[moz] fix: {简述}" && git push origin fix/{issue_number}-{brief}
4. CI 通过后创建 PRGitea API: POST /repos/{repo}/pullshead: fix/{issue_number}-{brief}, base: main
5. 等 Review
6. 提交 action report
# type/infrastructure label 路径(运维任务):
1. 根据 Issue body 中的错误来源和日志片段排查问题
2. 修复基础设施问题(如修复 CI runner 环境、恢复网络、重启服务等)
3. 修复后在 Issue 上 comment 说明修复方式和结果
4. 提交 action report
context:
issue_number, repo, issue_title, labels, issue_body, brief
```
**label 分流说明**issue_assigned handler 检查 label 中是否包含 `type/infrastructure`。如果是,走运维排查 stepsevent_type 设为 infrastructure_failureverify 始终 auto-pass 防递归);否则走编码 steps。
**编码路径 git 操作具体化说明**(§17 v3 补充):原 steps 只写「创建分支」「push」等抽象指令,agent 需要自己推导具体 git 命令。现在 steps 中写清楚完整 git 操作序列(checkout main → pull → checkout -b → commit → push),降低 agent 出错概率。系统不做分支管理(不通过 Gitea API 预创建分支),分支管理完全由 agent 自己执行。ToolchainApiSection 中新增 Git 操作说明段落作为通用参考。
#### 部署失败 → 运维
```
@@ -532,9 +553,10 @@ event_type: deploy_failure
action_type: deploy_failure
steps:
1. 检查 deploy 日志
2. 排查失败原因
3. 修复并重新部署
4. 提交 action report
2. 根据 deploy 日志判断失败原因类型:
a. 代码/配置问题(rsync 路径错、依赖缺失、启动失败)→ 修复 → 重新部署
b. 基础设施问题(Gitea 不可用、网络不通、磁盘满、SSH 故障)→ 在该仓库创建 Issue 指派 jiangwei-infra(见 §6.4),label 必须包含 type/infrastructure
3. 提交 action report — 报告中说明判断的原因类型和执行的操作
context:
repo, commit_sha, reason
```
@@ -577,6 +599,89 @@ context:
**spawn 说明**review_merged 仍会触发 spawnAgent 只需阅读通知),verify auto-pass 后标 done。未来可优化为 ticker 直接 auto-done 跳过 spawn。
### 6.4 基础设施 Issue 转交流程
当 ci_failure / deploy_failure 的 agent 在调查后发现失败原因是基础设施问题(非代码问题),需要创建 Gitea Issue 指派 jiangwei-infra。
#### Issue 提在哪里
**根据问题来源决定**——哪个仓库的 CI/部署失败了,Issue 就提到那个仓库。CI runner 是全局共享的(一个 Mac mini),但 Issue 挂在触发的仓库最自然。如果 runner 故障影响多个仓库,各仓库会各自触发 ci_failure task,姜维看到任何一个 Issue 就能定位全局问题。
#### Issue 格式规范
```markdown
## 问题描述
<简要描述问题现象>
## 错误来源
- 仓库: <repo>
- PR/Commit: <链接>
- CI/Deploy run: <Gitea Actions 页面链接>
## 日志关键片段
```
<错误日志摘要,不需全文,但要让排查者看到关键信息>
```
## 判断依据
<为什么判断为基础设施问题而非代码问题>
```
**必填字段**:问题描述、错误来源(含链接)、日志片段、判断依据。Issue body 不完整会导致姜维无法高效排查。
**label 要求**:必须包含 `type/infrastructure`,用于 issue_assigned handler 分流(见下)。
#### issue_assigned handler label 分流
当 Gitea Issue 指派触发 webhook 时,issue_assigned handler 检查 label
| label 包含 type/infrastructure | event_type | steps |
|---|---|---|
| 是 | infrastructure_failure | 运维排查:根据 Issue body 排查问题 → 修复 → Issue comment 说明修复方式 → action report |
| 否 | issue_assigned | 编码:创建分支 → 编码 → push → CI → PR → 等 Review → action report |
基础设施路径的 verify 始终 auto-pass(防递归,已有逻辑覆盖)。
⚠️ **label 分流当前为设计目标**toolchain_handler.py 尚未实现 issue_assigned 的 label 检查。当前只有 `_handle_infrastructure_failure`verify 失败时)创建 infrastructure_failure task。issue_assigned handler 的 label 分流在后续代码 PR 中实现。
⚠️ **label 预创建**:使用前需确认仓库中已创建名为 `type/infrastructure` 的 label。sanguo_moziplus_v2 仓库已创建(ID=98)。其他仓库使用前需先创建。
#### API 指令位置
Issue 创建的 API 调用方式(curl 示例)统一在 ToolchainApiSection 中,与 action_report / comment 指引并列。steps 指令中不重复 API 调用方式,只描述"做什么"。
#### Git 操作说明段落
ToolchainApiSection 中新增通用 Git 操作说明段落,作为 agent 执行 git 命令的参考:
```
### Git 操作说明
你的工作目录是开发目录。
标准分支操作流程:
git checkout main && git pull origin main # 从最新主干开始
git checkout -b fix/{branch_name} # 创建功能分支
# ... 写代码 ...
git add -A && git commit -m 'message' # 提交改动
git push origin {branch_name} # 推送到远程
⚠️ 不要在 main 分支上直接 commit。
```
**设计原则**:系统不做分支管理(不预创建分支、不做 checkout),分支管理完全由 agent 自己执行。ToolchainApiSection 提供通用 git 操作参考,steps 中写清楚具体操作序列。
#### Red Flags 补充
硬约束 Red Flags 表新增一条:
| Agent 想法 | Red Flag 驳回 |
|---|---|
| "CI/部署失败不是我代码的问题,我什么也不用做" | ❌ 错!即使是基础设施问题,你也必须创建 Issue 指派 jiangwei-infrabody 含错误来源链接 + 日志 + 判断依据),并在 action report 中说明。不能只报告"不是我的问题"就完事 |
---
## §7. _send_toolchain_task 函数设计
@@ -503,13 +503,13 @@ S1 和 S2 已完成(PR #85)。S3-S5 设计见下方 §11A。
"message": "L1 自蒸馏 cron。请执行:\n1. read ~/.sanguo_projects/sanguo_mozi/skills/skill-management/SKILL.md\n2. read ~/.sanguo_projects/sanguo_mozi/skills/skill-management/references/discover-l1.md\n3. 按 discover-l1.md 步骤执行自蒸馏\n4. 如有信号:蒸馏为 HOW 格式,使用 skill_workshop(action=create) 提交 draft proposal\n5. 如无有价值信号:不产出,这是正常的",
"timeoutSeconds": 600
},
"delivery": { "mode": "none" }
"delivery": { "mode": "announce" }
}
```
**设计要点**:
- `sessionTarget: "isolated"`:每次创建临时 session,不污染 main session context
- `delivery.mode: "none"`:L1 不需要通知任何人,proposal 存在 skill_workshop 中即可
- `delivery.mode: "announce"`:执行结果投递到 Control UI,保持可见性(早期使用 `none` 导致 cron 执行后零可见性,已修正)
- `timeoutSeconds: 600`:10 分钟足够(扫描 JSONL + 蒸馏 + 提交 proposal
- message 指引 read SKILL.md + discover-l1.mdagent 按 references 指南执行,不依赖 memory
@@ -533,11 +533,12 @@ S1 和 S2 已完成(PR #85)。S3-S5 设计见下方 §11A。
"message": "L2 整合审查 cron。请执行:\n1. read ~/.sanguo_projects/sanguo_mozi/skills/skill-management/references/discover-l2.md\n2. 按 discover-l2.md 步骤执行:\n a. skill_workshop(action=list, status=pending) 获取所有 L1 draft proposals\n b. 全量数据源扫描,识别跨 agent 共性模式\n c. 逐个审查 proposalapprove / merge / reject\n d. 全局提升检查(Recurrence-Count >= 3 的经验提升为规则)\n e. 知识缺口反馈到 knowledge-gaps.md",
"timeoutSeconds": 1200
},
"delivery": { "mode": "none" }
"delivery": { "mode": "announce" }
}
```
**设计要点**:
- `delivery.mode: "announce"`:审查决策结果投递到 Control UI,主公可见
- `timeoutSeconds: 1200`(20 分钟):L2 需要扫描全量数据源 + 审查多个 proposal,时间更长
- 庞统可以访问所有 agent 的 JSONL 和 skill_workshop proposals
@@ -561,11 +562,12 @@ S1 和 S2 已完成(PR #85)。S3-S5 设计见下方 §11A。
"message": "IMPROVE 每周引用追踪 cron。请执行:\n1. read ~/.sanguo_projects/sanguo_mozi/skills/skill-management/references/improve.md\n2. 按 improve.md 步骤执行:\n a. 扫描过去 7 天所有 agent 的 session JSONL,采集 Skill 引用信号\n b. 生成淘汰候选报告(30 天无引用的 Skill)\n c. 庞统审阅决策:quarantine / 保留观察 / 更新后保留\n d. 经验提升检查(被频繁引用 >= 5 次的 Skill\n e. 反馈知识缺口到 knowledge-gaps.md",
"timeoutSeconds": 1800
},
"delivery": { "mode": "none" }
"delivery": { "mode": "announce" }
}
```
**设计要点**:
- `delivery.mode: "announce"`:淘汰/提升报告投递到 Control UI
- `timeoutSeconds: 1800`(30 分钟):全量 JSONL 扫描是最重的操作
- 每周一次频率足够——Skill 引用变化不会很快
- 淘汰决策通过 skill_workshop quarantine 执行,提升决策通过手动编辑 AGENTS.md
@@ -0,0 +1,380 @@
---
title: "Issue-Centric Orchestration — Gitea Issue 替代黑板 DB 协作面"
created: 2026-06-19
version: v2.1 draft
status: draft
changelog: v2.1 修正 M1dispatcher 直接 SQL 声明)+ M2Phase 格式)+ S1/S2TaskAdapter 残留清理)
v2.0 纳入姜维+司马懿 Review 反馈 + 庞统 Repository 模式修正
v1.1 纳入姜维 Review 反馈
v1.0 初版
---
# Issue-Centric Orchestration
> **作者**: 庞统(副军师)🐦
> **日期**: 2026-06-19
> **定位**: 将黑板 DB 的协作面迁移到 Gitea Issuedaemon 逻辑保持不变
> **前置文档**: PRD-v3.0(共享意识空间)、§14 TaskTypeRegistry、§17 ToolchainHandler
---
## §1. 设计目标
| # | 目标 | 说明 |
|---|------|------|
| 1 | 黑板 DB 协作面迁移到 Gitea Issue | 需求、讨论、产出从黑板 DB 迁到 Issue |
| 2 | 成果物以 Gitea 为基础存放 | 分支 commit + PR |
| 3 | webhook 部分替代 ticker | 主动触发替代轮询,ticker 保留兜底 |
| 4 | task 状态 + spawner 逻辑不变 | daemon 内部状态机不变 |
| 5 | prompt 改造 | 黑板 API 引用改为 Gitea API,告知 agent 使用 Gitea 协作 |
**核心原则**: 只有数据存储位置变了(黑板 DB → Gitea Issue),daemon 的调度逻辑(dispatcher/ticker/spawner)不变。
---
## §2. 现状分析
### 2.1 黑板 DB 当前承担的角色
根据 PRD-v3.0,黑板是**共享意识空间**——所有 agent 通过它读写状态、感知变化、协调工作。
黑板 DB 包含 14 张表:
| 表 | 用途 | 分类 |
|---|------|------|
| tasks | 任务(标题、描述、状态、指派、retry) | 协作面 + 执行面 |
| comments | 讨论、@mention、action_report | 协作面 |
| outputs | 产出物(文本摘要、文件路径) | 协作面 |
| events | 事件流(SSE 推送) | 协作面 |
| reviews | 审查记录(verdict、round、consensus | 执行面 |
| checkpoints | 阶段审查(approve/reject | 执行面 |
| decisions | 决策记录 | 执行面 |
| observations | 风险观察 | 执行面 |
| experiences | 经验沉淀 | 执行面 |
| routing_decisions | 路由记录 | 执行面 |
| task_attempts | 重试历史 | 执行面 |
| mention_queue | @mention 队列 | 执行面 |
| experience_tags | 经验标签 | 执行面(§19 已标记废弃) |
| agents | Agent 注册信息 | 执行面 |
**协作面**tasks/comments/outputs/events= 迁移到 Gitea Issue
**执行面**reviews/checkpoints/decisions 等)= 保留在 daemon 内部
### 2.2 daemon 数据访问方式
当前 daemon 三个核心模块如何读写黑板 DB:
| 模块 | 读什么 | 怎么读 |
|------|-------|-------|
| ticker | pending task 列表 | `SELECT * FROM tasks WHERE status='pending'` (SQLite) |
| dispatcher | task 详情(title/description/must_haves | `Task.from_row(row)` 从 SQLite 行构建 |
| spawner | task 上下文构建 prompt | 从 task 对象的 title/description/must_haves 字段 |
| 模块 | 写什么 | 怎么写 |
|------|-------|-------|
| dispatcher | task statuspending→claimed→working | `UPDATE tasks SET status=?` |
| spawner | task statusworking→done/failed | `UPDATE tasks SET status=?` |
| handler | comment / output | `INSERT INTO comments/outputs` |
**关键发现**: daemon 大量依赖 `SELECT * FROM tasks WHERE status=?` 这种 SQL 查询来发现和调度 task。如果数据源迁到 Gitea Issue,这些查询的方式会变(从 SQLite 变为 Gitea API 或本地索引),但**查询的语义和返回的数据结构不变**。
---
## §3. 目标架构
### 3.1 分层
```
Gitea(协作介质,替代黑板 DB 协作面)
┌──────────────────────────────────────────┐
│ Issue #42: "实现功能 A" │
│ body: 需求描述 + 验收标准 │
│ assignee: zhangfei-dev │
│ labels: type/feat, priority/P2 │
│ comments: 讨论、@mention、进展汇报 │
│ │
│ 分支: fix/42-feature-a │
│ PR #43: fix/42 → main │
│ CI: lint + test │
│ Review: APPROVE / REQUEST_CHANGES │
│ → merge → Issue auto-close │
└──────────────────────────────────────────┘
↕ webhook(被动) ↕ API(主动)
┌──────────────────────────────────────────┐
│ daemon(执行引擎,内部状态管理不变) │
│ │
│ task_state(轻量索引,替代 tasks 表): │
│ issue_number → status, branch, retry │
│ │
│ 执行面表(不变): │
│ reviews, checkpoints, decisions, │
│ observations, experiences, │
│ routing_decisions, task_attempts │
│ │
│ 调度逻辑(不变): │
│ ticker → 扫 task_state → dispatch │
│ dispatcher → 读 Gitea Issue → spawn │
│ spawner → 读 Gitea Issue → prompt │
└──────────────────────────────────────────┘
```
### 3.2 数据映射
| 黑板 DB | Gitea 对应 | 迁移方式 |
|---------|-----------|---------|
| tasks.title | Issue.title | 直接对应 |
| tasks.description | Issue.body | 直接对应 |
| tasks.assignee | Issue.assignee | 直接对应 |
| tasks.status (pending/working/review/done) | daemon task_state 内部维护 | Issue open/closed 只表示生命周期 |
| tasks.priority | Issue label (priority/P0-P3) | label 模拟 |
| tasks.must_haves (JSON) | daemon task_state 内部存储 | daemon 专用元数据 |
| tasks.depends_on | Issue blocked_by | Gitea 原生 dependency |
| tasks.parent_task | Issue body 引用(如 `Parent: #42` | 约定 |
| tasks.retry_count / dispatch_count | daemon task_state 内部维护 | 执行面数据 |
| comments | Issue comment | 直接对应 |
| outputs | 分支 commit(代码/文档)+ Issue comment(摘要) | 成果物载体迁移 |
| events | webhook | 主动推送替代 SSE |
### 3.3 数据访问层改造:Repository 模式换底
**设计原则**:改造现有 RepositoryQueries/Blackboard 类)的实现,不新增中间层。
当前数据访问层已有 Repository 模式的基础——`Blackboard` 类和 `Queries` 类封装了所有数据访问,上层(dispatcher/spawner/ticker)通过方法调用(`queries.pending_dispatchable()``blackboard.get_task()`),不直接写 SQL。
改造做法:**Repository 接口不变,实现从 SQLite-only 改为 Gitea + SQLite。**
```
现在:
dispatcher → Queries(SQLite) → 黑板 DB
改造后:
dispatcher → Queries(Gitea-backed) → Gitea API(协作数据)+ SQLite(执行状态)
```
上层代码**基本**不用改。但有一个前置条件:dispatcher.py 中存在约 20 处直接操作 tasks 表的 SQL(绕过 Queries 类,如 `SELECT assignee FROM tasks``UPDATE tasks SET status=?`)。这些直接 SQL 需要先迁移到 Queries 方法调用,才能实现 Repository 换底。此项作为 Phase 1 的前置工作。
Queries 内部决定数据从哪来:
| 数据类型 | 来源 | 方式 |
|---------|------|------|
| title / description / assignee / labels | Gitea Issue | API 读取(webhook 触发时缓存) |
| comment / 讨论 | Gitea Issue comment | API 读取 |
| status / retry_count / dispatch_count | 本地 SQLite | 原有逻辑不变 |
| daemon_meta(原 must_haves | 本地 SQLite | 原有逻辑不变 |
**本地 SQLite 表(执行状态,Gitea 没有的)**:
```sql
CREATE TABLE task_state (
issue_number INTEGER, -- Gitea Issue 编号
repo TEXT, -- 仓库名
status TEXT DEFAULT 'pending', -- daemon 内部状态机
retry_count INTEGER DEFAULT 0,
dispatch_count INTEGER DEFAULT 0,
max_retries INTEGER DEFAULT 2,
daemon_meta TEXT, -- JSONevent_type, steps 等 daemon 元数据)
issue_body_cache TEXT, -- 缓存的 Issue body(优化用,可失效重拉)
issue_updated_at TEXT, -- Gitea Issue 的 updated_at(缓存失效判断)
created_at TEXT,
updated_at TEXT,
PRIMARY KEY (issue_number, repo)
);
```
**为什么不用 TaskAdapter**Repository 内部已经把 Gitea 数据 + 本地执行状态合并成 Task 对象返回。上层调用 `queries.get_task(issue_number)` 得到的 Task 对象和现在一模一样——有 title、有 description、有 status。不需要额外 adapter 层。
---
## §4. 流程设计
### 4.1 创建 Task
```
① 庞统/主公在 Gitea 创建 Issue + 指派 agent
② Gitea webhook: issues/assigned
③ daemon toolchain handler 收到 webhook
→ 在 task_state 插入一行(issue_number, repo, assignee, status=pending
④ ticker 扫 task_state 发现 pending → dispatch → spawn agent
```
**和现在的区别**: 当前是庞统在黑板 API 创建 task。改造后是庞统在 Gitea 创建 Issuewebhook 自动触发 daemon 建索引。
### 4.2 执行 Task
```
① dispatcher 扫 task_state 发现 pending task
② spawner 从 Gitea API 读 Issue body(需求描述)
③ spawner 用 Issue body 构建 prompt(替代从黑板 DB 读 description
→ prompt 结构: Issue body(需求)+ PromptSection 注入(工作流程、约束、API 指引)
④ agent 收到 prompt → 执行
⑤ agent 在 Gitea Issue comment 汇报进展(替代黑板 comment)
⑥ daemon 更新 task_state status=working
```
### 4.3 审查
```
① agent 编码完成 → push 到分支 → 创建 PR
② Gitea webhook: pull_request/opened
→ daemon 更新 task_state status=review
③ Reviewer 在 Gitea 做 PR Review
④ Gitea webhook: pull_request_review
→ daemon 根据 Review 结果更新 task_state
⑤ Review 通过 → PR merge
→ Gitea 自动关闭 Issue
→ Gitea webhook: issues/closed
→ daemon 更新 task_state status=done
```
**commit message 约定**(司马懿 S3):Gitea PR merge 自动关闭 Issue 需要 commit message 包含 `Closes #N``Fixes #N` 关键词。agent 创建 PR 时在描述中加上此约定,确保 merge 后 Issue 自动关闭。
**审查统一走 PR Review**——不区分设计审查和代码审查,所有成果物都在分支上,Reviewer 一次性审。
### 4.4 CI 失败处理
```
① PR 创建 → CI 自动跑
② CI 失败 → Gitea webhook: pull_requestCI status
→ daemon toolchain handler 创建 ci_failure toolchain task
→ 指派给 PR 作者
→ agent 按 ci_failure steps 处理(已有逻辑,不变)
③ agent 修复 → push 到同分支 → PR 自动更新 → CI 重跑
```
### 4.5 ticker 兜底
webhook 可能丢失或延迟。ticker 保留原有逻辑,改为:
- 扫 `task_state` 中 status=pending 的记录(替代扫黑板 tasks 表)
- 扫 `task_state` 中 status=working 但超时的记录
- 如果发现 Gitea Issue 已 closed 但 task_state 还是 working → 更新为 done
---
## §5. daemon 需要改的地方
**原则: daemon 调度逻辑不变,只改数据访问层。**
### 5.1 数据访问层改造
| 模块 | 现在 | 改造后 | 影响范围 |
|------|------|-------|---------|
| `queries.pending_dispatchable()` | `SELECT * FROM tasks WHERE status='pending'` | `SELECT * FROM task_state WHERE status='pending'` | SQL 改表名 |
| `Task.from_row(row)` 构建 task 对象 | 从 tasks 表行直接取 title/description | 从 task_state 取 issue_number → 调 Gitea API 读 Issue title/body | 需要新增 Gitea API 调用 |
| `UPDATE tasks SET status=?` | 直接更新 SQLite | 更新 task_stateSQLite | SQL 改表名 |
| `INSERT INTO comments` | 写黑板 DB | 改为 Gitea Issue comment API | 需要新增 Gitea API 调用 |
### 5.2 ⚠️ 需要讨论的改造点
以下是因为数据源变了,daemon 实现需要调整的地方:
**P1: spawner 每次 spawn 都要调 Gitea API 读 Issue body**
当前 spawner 从 SQLite 读 task description(微秒级)。改为从 Gitea API 读(毫秒级,HTTP 请求)。
- **方案 A**: 每次 spawn 时实时调 Gitea API。简单但慢
- **方案 B**: webhook 触发时缓存 Issue body 到 `task_state.issue_body_cache` + `issue_updated_at`。spawn 时从缓存读
- **缓存失效**: spawner 构建 prompt 时比对 `issue_updated_at` 和 Gitea API 的 Issue `updated_at`,不匹配才重新拉取(正常情况 Issue body 创建后不改,开销可忽略)
- **推荐**: 方案 B + updated_at 校验
**P2: Repository 内部数据合并**
Queries 类内部改造——`get_task()` 方法从 Gitea API(或缓存)读 title/body,从 task_state 表读 status/retry_count,合并成 Task 对象返回。上层(dispatcher/spawner)无感知。
这是标准的 Repository 模式——接口不变(`get_task(id)` 返回 Task 对象),实现换底(从 SQLite 单源改为 Gitea + SQLite 双源)。不新增 TaskAdapter 类——Queries 类本身就是 Repository,内部合并是职责内的事。
**P3: agent 的 prompt 中引用黑板 API 的地方需要改**
PromptSection 中有多处 `POST localhost:8083/api/projects/.../tasks/.../comments`(黑板 API)。这些要改为 Gitea API
- `task_handler.py` TaskApiSection: `POST .../status``POST .../outputs` → 不需要(daemon 通过 webhook 自动感知状态)
- `toolchain_handler.py` ToolchainApiSection: `POST .../comments`action report)→ 改为 `POST Gitea API .../issues/.../comments`
- `toolchain_handler.py` ToolchainApiSection: `POST .../outputs` → 改为"push 到分支"指引
**P4: comments 表的 @mention 机制**
当前 @mention 通过黑板 `mention_queue` 表排队。改造后 @mention 通过 Gitea Issue/PR commentwebhook 自然触发)。但 mention_queue 的消费逻辑(ticker 扫描 → 通知 → agent 处理)需要适配。
- **方案**: mention_queue 保留,但数据来源从黑板 comment 改为 Gitea webhook payload
- **⚠️ 适配层**: Gitea webhook payload 中的 comment body 是完整 markdown 文本(不像黑板 comment 是结构化 JSON,有 comment_type、author 等字段)。mention_queue 消费侧需要适配:从 webhook payload 的 `comment.body` 中正则提取 @mention,而非 SQL WHERE 精确查询。这层适配在 Phase 4 mention 迁移时细化
- **影响**: ticker 中的 mention 处理逻辑需要适配
- **action_report 识别**(司马懿 S2):黑板 comment 有结构化 `comment_type=action_report` 字段,Gitea comment 只有 markdown body。迁移后用 **body 中的固定标记**识别,如 `<!-- action_report -->` 或约定 body 以 `[Action Report]` 开头。具体格式在 Phase 4 实施时确定。
---
## §6. prompt 改造
### 6.1 受影响的 PromptSection
| Section | 文件 | 当前内容 | 改造后 |
|---------|------|---------|-------|
| TaskApiSection | task_handler.py | 黑板 APIstatus 回写、outputs 提交) | 删除 status 回写(daemon 自动管);outputs 改为 git push |
| ToolchainApiSection | toolchain_handler.py | 黑板 APIaction_report comment、outputs | action_report 改为 Issue commentoutputs 改为 git push |
| TaskConstraintsSection | task_handler.py | "blackboard comment" 引用 | 改为 "Issue/PR comment" |
| ToolchainConstraintsSection | toolchain_handler.py | 已禁止 Mail | 同时告知 agent 使用 Gitea 协作 |
### 6.2 agent prompt 新增指引
agent 需要知道工作方式变了。新增一个通用 section(或加入现有 constraints section):
```
## 协作方式
- 你的任务通过 Gitea Issue 管理
- 需求描述在 Issue body 中
- 进展汇报通过 Issue comment
- 代码产出通过分支 commit + PR
- 审查通过 PR Review
- 不要使用黑板 API,不要使用 Mail API
```
---
## §7. Issue ↔ 分支 ↔ PR 关系
| 场景 | Issue : 分支 : PR |
|------|------------------|
| 简单任务(bugfix、小功能) | 1 : 1 : 1 |
| 复杂任务(多阶段) | 1 : 1 : N(分阶段提交 PR,同一个分支) |
| 极复杂任务(需拆解) | 1 : N : N(Issue body 列出子任务,每个一个分支+PR) |
**默认 1:1:1**。分支命名规范不变:`fix/{issue_number}-{brief}`
---
## §8. 不做的事
| 不做 | 理由 |
|------|------|
| 不做数据迁移 | 主公确认当前无正式使用数据 |
| 不做 Issue 状态 labelstatus/xxx | 中间状态 daemon 内部管,Issue 只有 open/closed |
| 不改 Mail | Mail 职责不变。Issue-centric 模式下 agent 不用 Mail(通过 Issue/PR comment 协作)。Mail 剩余职责:非 Gitea 相关的 agent 间点对点通知(如庞统通知赵云准备数据) |
| 不改前端(本阶段) | 前端改造独立于后端,后续设计 |
| 不做存量 task 退役 | 原 task 流程和 Issue 流程可共存,原 task 自然退役 |
| 不改 experiences/checkpoints/decisions 表 | 执行面表保留在 daemon,不受影响 |
---
## §9. 实施路径
| 阶段 | 内容 | 依赖 |
|------|------|------|
| 阶段 | 内容 | 依赖 |
|------|------|------|
| Phase 0 | webhook 权限配置(主公手动配)+ CI status webhook 验证(确认 Gitea CI status 变化触发 webhook | 设计 Review 通过 |
| Phase 1 | dispatcher.py 直接 SQL(约 20 处)迁移到 Queries 方法调用 + task_state 表创建 + Queries/Blackboard 内部改造(Gitea + SQLite 双源)+ must_haves→daemon_meta 重命名(17 文件 80 处,机械替换,需 CI 覆盖) | Phase 0 |
| Phase 2 | dispatcher/ticker 数据源从 tasks 表切换到 task_state | Phase 1 |
| Phase 3 | spawner 读 Issue body 构建 prompt(替代读黑板 description+ issue_updated_at 缓存失效机制 | Phase 2 |
| Phase 4 | prompt 改造(黑板 API → Gitea API+ mention_queue 适配(action_report body 标记约定) | Phase 3 |
| Phase 5 | 验证 + 清理废弃的黑板协作面表 | Phase 4 |
每个 Phase 独立可验证,出问题可以回退。
---
## §10. 风险评估
| 风险 | 等级 | 缓解 |
|------|------|------|
| Gitea API 不可用时 daemon 完全瘫痪 | 中 | webhook 触发时缓存 Issue body + issue_updated_at 校验(P1 方案 B),减少运行时 Gitea API 依赖 |
| Gitea webhook 丢失 | 低 | ticker 兜底扫描 |
| task_state 和 Gitea Issue 状态不一致 | 中 | ticker 定期校验(发现 Issue closed 但 index 未更新则修复) |
| spawner 性能下降(Gitea API 调用) | 低 | 方案 B 缓存 Issue bodyspawn 时不调 Gitea API |
| 原 task 流程和新 Issue 流程共存期混乱 | 中 | 可以限定只在特定项目中启用 Issue 模式,逐步切换 |
+57 -32
View File
@@ -778,9 +778,8 @@ def _send_deploy_failure_task(repo: str, pr_number: int, pr_title: str, reason:
action_type="deploy_failure",
steps=[
"检查 deploy 日志",
"排查失败原因",
"修复并重新部署",
"提交 action reportPOST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/commentscomment_type=action_report",
"根据 deploy 日志判断失败原因类型:\n a. 代码/配置问题(rsync 路径错、依赖缺失、启动失败)→ 修复 → 重新部署\n b. 基础设施问题(Gitea 不可用、网络不通、磁盘满、SSH 故障)→ 在该仓库创建 Issue 指派 jiangwei-infra(见下方「需要创建 Issue 时」),label 必须包含 type/infrastructure",
"提交 action reportPOST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/commentscomment_type=action_report)— 报告中说明判断的原因类型和执行的操作",
],
context_data={
"repo": repo,
@@ -997,30 +996,58 @@ async def _handle_issues(payload: Dict[str, Any]) -> None:
"brief": brief,
})
title = f"Issue 指派: {issue_title} ({repo}#{issue_number})"
_send_toolchain_task(
to_agent=assignee,
title=title,
description=text,
event_type="issue_assigned",
action_type="issue_assigned",
steps=[
f"创建分支 fix/{issue_number}-{brief}",
"编码 + 写 UT",
"push → 等 CI",
f"CI 通过后创建 PRGitea API: POST /repos/{repo}/pulls",
"等 Review",
# 检查是否是基础设施 Issue(按 label 分流)
is_infrastructure = any("infrastructure" in lbl.lower() for lbl in labels_list)
if is_infrastructure:
infra_steps = [
"根据 Issue body 中的错误来源和日志片段排查问题",
"修复基础设施问题(如修复 CI runner 环境、恢复网络、重启服务等)",
"修复后在 Issue 上 comment 说明修复方式和结果",
"提交 action reportPOST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/commentscomment_type=action_report",
],
context_data={
"issue_number": issue_number,
"repo": repo,
"issue_title": issue_title,
"labels": labels,
"issue_body": issue_body or "(无描述)",
"brief": brief,
},
)
]
title = f"基础设施 Issue: {issue_title} ({repo}#{issue_number})"
_send_toolchain_task(
to_agent=assignee,
title=title,
description=text,
event_type="infrastructure_failure",
action_type="infrastructure_failure",
steps=infra_steps,
context_data={
"issue_number": issue_number,
"repo": repo,
"issue_title": issue_title,
"labels": labels,
"issue_body": issue_body or "(无描述)",
"brief": brief,
},
)
else:
title = f"Issue 指派: {issue_title} ({repo}#{issue_number})"
_send_toolchain_task(
to_agent=assignee,
title=title,
description=text,
event_type="issue_assigned",
action_type="issue_assigned",
steps=[
f"在开发目录执行 git 操作:\n a. git checkout main && git pull origin main\n b. git checkout -b fix/{issue_number}-{brief}",
"编码 + 写 UT",
f"git add -A && git commit -m \"[moz] fix: {issue_title[:30]}\" && git push origin fix/{issue_number}-{brief}",
f"CI 通过后创建 PRGitea API: POST /repos/{repo}/pullshead: fix/{issue_number}-{brief}, base: main",
"等 Review",
"提交 action reportPOST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/commentscomment_type=action_report",
],
context_data={
"issue_number": issue_number,
"repo": repo,
"issue_title": issue_title,
"labels": labels,
"issue_body": issue_body or "(无描述)",
"brief": brief,
},
)
elif action == "opened":
if "部署失败" in issue_title:
@@ -1043,9 +1070,8 @@ async def _handle_issues(payload: Dict[str, Any]) -> None:
action_type="deploy_failure",
steps=[
"检查 deploy 日志",
"排查失败原因",
"修复并重新部署",
"提交 action reportPOST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/commentscomment_type=action_report",
"根据 deploy 日志判断失败原因类型:\n a. 代码/配置问题(rsync 路径错、依赖缺失、启动失败)→ 修复 → 重新部署\n b. 基础设施问题(Gitea 不可用、网络不通、磁盘满、SSH 故障)→ 在该仓库创建 Issue 指派 jiangwei-infra(见下方「需要创建 Issue 时」),label 必须包含 type/infrastructure",
"提交 action reportPOST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/commentscomment_type=action_report)— 报告中说明判断的原因类型和执行的操作",
],
context_data={
"repo": repo,
@@ -1126,9 +1152,8 @@ async def _handle_issue_comment(payload: Dict[str, Any]) -> None:
action_type="ci_failure",
steps=[
"查看完整 CI 日志(PR 页面或 Gitea Actions 页面)",
"修复失败的测试",
"push → CI 自动重跑",
"提交 action reportPOST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/commentscomment_type=action_report",
"根据 CI 日志判断失败原因类型:\n a. 代码问题(lint/test 失败)→ 修复失败的测试 → push 到原分支 → CI 自动重跑\n b. 基础设施问题(runner 环境/Python/venv/Gitea/网络故障)→ 在该仓库创建 Issue 指派 jiangwei-infra(见下方「需要创建 Issue 时」),label 必须包含 type/infrastructure",
"提交 action reportPOST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/commentscomment_type=action_report)— 报告中说明判断的原因类型和执行的操作",
],
context_data={
"pr_number": issue_number,
+28
View File
@@ -166,6 +166,33 @@ class ToolchainApiSection:
"",
"⚠️ 不要使用 Mail API(飞鸽传书)。所有协作通过 Gitea 留痕。",
"",
"### 需要创建 Issue 时",
"",
"如果步骤中要求创建 Issue 指派他人(如 jiangwei-infra):",
"```bash",
f'curl -s -X POST "{_GITEA_BASE}/repos/{{repo}}/issues" \\',
' -H "Authorization: token <your-token>" \\',
' -H "Content-Type: application/json" \\',
' -d \'{"title": "[moz] infra: 简述问题", "body": "## 问题描述\\n\\n<简要描述问题现象>\\n\\n## 错误来源\\n\\n- 仓库: <repo>\\n- PR/Commit: <链接>\\n- CI/Deploy run: <Gitea Actions 页面链接>\\n\\n## 日志关键片段\\n\\n```<错误日志摘要>```\\n\\n## 判断依据\\n\\n<为什么判断为基础设施问题>", "assignees": ["jiangwei-infra"], "labels": [<label_id>]}\'',
"```",
"",
"⚠️ Issue body 必须包含错误来源链接(PR/Commit + CI run),让排查者能直接看到全貌。",
"⚠️ label 数字 ID 先 GET /repos/{repo}/labels 查询 type/infrastructure 对应的 ID。",
"",
"### Git 操作说明",
"",
"你的工作目录是开发目录(如 ~/.openclaw/sanguo_projects/sanguo_moziplus_v2/)。",
"标准分支操作流程:",
"```bash",
"git checkout main && git pull origin main # 从最新主干开始",
"git checkout -b fix/{branch_name} # 创建功能分支",
"# ... 写代码 ...",
"git add -A && git commit -m 'message' # 提交改动",
"git push origin {branch_name} # 推送到远程",
"```",
"",
"⚠️ 不要在 main 分支上直接 commit。",
"",
]
return "\n".join(lines)
@@ -218,6 +245,7 @@ class ToolchainConstraintsSection:
'| “我已经知道了” | ❌ 知道不等于执行。执行步骤 + 提交 action report 才算完成 |',
'| “步骤太多了,选几个做就行” | ❌ 错!必须逐条执行,不可跳过 |',
'| “这个步骤不适用于当前情况” | ❌ 如果确实不适用,在 action report 中说明原因,但其他步骤必须执行 |',
'| “CI/部署失败不是我代码的问题,我什么也不用做” | ❌ 错!即使是基础设施问题,你也必须创建 Issue 指派 jiangwei-infrabody 含错误来源链接 + 日志 + 判断依据),并在 action report 中说明。不能只报告“不是我的问题”就完事 |',
"",
]
return "\n".join(lines)
+95
View File
@@ -523,3 +523,98 @@ class TestFullPromptBuild:
# Must have constraints with Red Flags
assert "Red Flags" in prompt
assert "强制要求" in prompt
# ---------------------------------------------------------------------------
# §17 v2: CI/deploy failure branching + issue label routing + Issue API guidance
# ---------------------------------------------------------------------------
class TestCiFailureBranching:
"""ci_failure steps should include a/b branching guidance."""
def test_ci_failure_steps_contain_branching(self):
source_file = PROJECT_ROOT / "src" / "api" / "toolchain_routes.py"
source = source_file.read_text()
assert '基础设施问题' in source
assert 'type/infrastructure' in source
assert 'jiangwei-infra' in source
class TestDeployFailureBranching:
"""deploy_failure steps should include a/b branching guidance."""
def test_deploy_failure_steps_contain_branching(self):
source_file = PROJECT_ROOT / "src" / "api" / "toolchain_routes.py"
source = source_file.read_text()
count = source.count('基础设施问题(Gitea 不可用')
assert count >= 2, f'Expected >=2 deploy_failure branching, found {count}'
class TestIssueAssignedLabelRouting:
"""issue_assigned handler should route by type/infrastructure label."""
def test_label_check_in_source(self):
source_file = PROJECT_ROOT / "src" / "api" / "toolchain_routes.py"
source = source_file.read_text()
assert 'is_infrastructure' in source
assert 'infrastructure_failure' in source
assert '基础设施 Issue' in source
def test_normal_issue_keeps_coding_steps(self):
source_file = PROJECT_ROOT / "src" / "api" / "toolchain_routes.py"
source = source_file.read_text()
assert 'git checkout -b fix/' in source
assert 'issue_assigned' in source
class TestToolchainApiIssueGuidance:
"""ToolchainApiSection should include Issue creation guidance."""
def test_has_issue_creation_section(self):
source_file = PROJECT_ROOT / "src" / "daemon" / "toolchain_handler.py"
source = source_file.read_text()
assert "需要创建 Issue 时" in source
assert "/issues" in source
assert "jiangwei-infra" in source
assert "type/infrastructure" in source
def test_issue_body_template_mentions_required_fields(self):
source_file = PROJECT_ROOT / "src" / "daemon" / "toolchain_handler.py"
source = source_file.read_text()
assert "错误来源" in source
assert "判断依据" in source
class TestRedFlagsInfrastructure:
"""Red Flags should include the 'not my code' entry."""
def test_has_infrastructure_red_flag(self):
source_file = PROJECT_ROOT / "src" / "daemon" / "toolchain_handler.py"
source = source_file.read_text()
assert "不是我代码的问题" in source
assert "基础设施问题" in source
class TestGitOperationGuidance:
"""ToolchainApiSection should include Git operation guidance."""
def test_has_git_operation_section(self):
source_file = PROJECT_ROOT / "src" / "daemon" / "toolchain_handler.py"
source = source_file.read_text()
assert "Git 操作说明" in source
assert "git checkout main" in source
assert "git pull origin main" in source
assert "git checkout -b" in source
def test_has_no_main_commit_warning(self):
source_file = PROJECT_ROOT / "src" / "daemon" / "toolchain_handler.py"
source = source_file.read_text()
assert "不要在 main 分支上直接 commit" in source
def test_issue_assigned_steps_have_git_commands(self):
source_file = PROJECT_ROOT / "src" / "api" / "toolchain_routes.py"
source = source_file.read_text()
assert 'git checkout main && git pull origin main' in source
assert 'git checkout -b fix/' in source
assert 'git add -A && git commit' in source
assert 'git push origin fix/' in source