2026-10-18 22:28:28 +08:00
|
|
|
|
# 图模式(独立功能)
|
|
|
|
|
|
|
|
|
|
|
|
> 2026-10-18 新增。**这一套与现有「项目机制」完全并列**:不读写 `goal.json`、`tasks.json`、`collabd-state.json`,不参与六道闸,不接管常驻循环,不改变现有任何会话的行为。
|
|
|
|
|
|
> 停用方式:不调用它就行;它没有常驻进程、没有注册任何钩子、没有改任何现有文件。
|
|
|
|
|
|
|
|
|
|
|
|
## 一、它解决什么
|
|
|
|
|
|
|
|
|
|
|
|
现有机制是「一棒干一堆、由会话读摘要决定下一棒」。图模式把这层换成:
|
|
|
|
|
|
|
|
|
|
|
|
- **节点**:一块独立的活,带自己的**域**(允许写哪些目录)和**判据**。
|
|
|
|
|
|
- **边**:节点之间的依赖;依赖全 done 才放行。
|
|
|
|
|
|
- **状态**:写在一份图上,跨会话共享,不依赖任何会话的上下文。
|
|
|
|
|
|
|
|
|
|
|
|
于是可以做到:**一批就绪节点同时干、干完各自回报、下一批自动放行**。
|
|
|
|
|
|
|
|
|
|
|
|
## 二、怎么用
|
|
|
|
|
|
|
|
|
|
|
|
工作区参数 `--ws` 指向要被推进的工作区根目录。图落在 `<ws>/.workbuddy/graph/<gid>/`。
|
|
|
|
|
|
|
|
|
|
|
|
### 1、建图
|
|
|
|
|
|
|
|
|
|
|
|
按判据建(每条判据一个节点,默认无依赖、无域):
|
|
|
|
|
|
|
|
|
|
|
|
python graph/graphctl.py init --ws "<ws>" --title "目标名" --kpi "判据A;判据B;判据C"
|
|
|
|
|
|
|
|
|
|
|
|
按节点定义建(要并行、要依赖、要域,就用这个):
|
|
|
|
|
|
|
|
|
|
|
|
python graph/graphctl.py init --ws "<ws>" --title "目标名" --nodes-json - <<'JSON'
|
|
|
|
|
|
{
|
|
|
|
|
|
"max_parallel": 3,
|
|
|
|
|
|
"nodes": [
|
|
|
|
|
|
{"id": "A", "title": "改界面", "domain": ["ui/"], "accepts": ["页面能打开"], "deps": []},
|
|
|
|
|
|
{"id": "B", "title": "改文档", "domain": ["docs/"], "accepts": ["索引已登记"], "deps": []},
|
|
|
|
|
|
{"id": "C", "title": "改服务", "domain": ["server/"], "accepts": ["本地能起"], "deps": ["A"]},
|
|
|
|
|
|
{"id": "D", "title": "汇总", "domain": ["docs/index/"], "accepts": ["三处齐"], "deps": ["A","B","C"]}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
JSON
|
|
|
|
|
|
|
|
|
|
|
|
### 2、校验
|
|
|
|
|
|
|
|
|
|
|
|
python graph/graphctl.py check --ws "<ws>" --gid "<gid>"
|
|
|
|
|
|
|
|
|
|
|
|
报三件硬错(环、依赖指向不存在的节点、状态非法)和三类警告(没有域、没有判据、两个节点域重叠)。
|
|
|
|
|
|
|
|
|
|
|
|
### 3、算这一批派谁
|
|
|
|
|
|
|
|
|
|
|
|
python graph/graphctl.py ready --ws "<ws>" --gid "<gid>"
|
|
|
|
|
|
|
|
|
|
|
|
输出 `ready`(这一批可以同时开工的节点)、`backlog`(就绪但被并发上限挡住)、`waiting`(还差什么)。
|
|
|
|
|
|
|
|
|
|
|
|
### 4、开一个节点、回报
|
|
|
|
|
|
|
|
|
|
|
|
python graph/graphctl.py start --ws "<ws>" --gid "<gid>" --node A --by "执行会话-xxx"
|
|
|
|
|
|
python graph/graphctl.py report --ws "<ws>" --gid "<gid>" --node A --state done --evidence "页面 1440 宽截图在 ui/shot.png"
|
|
|
|
|
|
|
|
|
|
|
|
回报 `done` 后会立刻返回下一批的 `ready`,这就是图在往前走的信号。
|
|
|
|
|
|
|
|
|
|
|
|
### 5、看状态
|
|
|
|
|
|
|
|
|
|
|
|
python graph/graphctl.py list --ws "<ws>"
|
|
|
|
|
|
python graph/graphctl.py show --ws "<ws>" --gid "<gid>"
|
|
|
|
|
|
|
|
|
|
|
|
## 三、就绪的四个条件
|
|
|
|
|
|
|
|
|
|
|
|
1. 依赖全部 `done`。
|
|
|
|
|
|
2. 节点自己是 `pending`。
|
|
|
|
|
|
3. 域不与任何 `running` 节点重叠(`docs/` 与 `docs/ui/` 算重叠)。
|
|
|
|
|
|
4. 加上在跑的节点后,不超过 `max_parallel`(默认 3)。
|
|
|
|
|
|
|
|
|
|
|
|
## 四、与现有机制的关系
|
|
|
|
|
|
|
|
|
|
|
|
| 事项 | 现有机制 | 图模式 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| 目标定义 | `goal.json` | 图文件里的 `title` / `nodes` |
|
|
|
|
|
|
| 任务台账 | `tasks.json` | 图里每个节点的 `status` + `events.jsonl` |
|
|
|
|
|
|
| 派活决策 | 检查会话读摘要判断 | `ready` 按图算 |
|
|
|
|
|
|
| 触发 | 常驻 + 六道闸 + 静默 2 分钟 | 调用方驱动(人或会话),无后台进程 |
|
|
|
|
|
|
| 会话创建 | 自动化排期 | 由调用方决定(图不管怎么开会话) |
|
|
|
|
|
|
| 域锁 | 开工时声明 | 同左,节点的 `domain` 直接喂给开工命令 |
|
|
|
|
|
|
|
|
|
|
|
|
**两套可以同时存在**:图模式不读也不改现有那三份文件,现有机制也永远不会看到 `graph/` 目录。
|
|
|
|
|
|
|
2026-10-19 08:18:57 +08:00
|
|
|
|
## 五、怎么跑测试
|
|
|
|
|
|
|
|
|
|
|
|
python graph/test_graphctl.py -v
|
|
|
|
|
|
|
|
|
|
|
|
全绿应看到 `Ran 49 tests ... OK`,用时 20 秒上下(每条用例起一次子进程)。
|
|
|
|
|
|
|
|
|
|
|
|
测试只往临时目录写:`<GRAPH_TEST_TMP>/graph-test-<pid>/<用例名>`,默认 `GRAPH_TEST_TMP` = `AIProject/ai1net-dsh-server/tmp`,由每条用例的 `tearDown` + 进程退出的 `atexit` 兜底删除。想换落点就设环境变量 `GRAPH_TEST_TMP`。
|
|
|
|
|
|
|
|
|
|
|
|
清残留在本机是常态:跑完后 `tmp/` 下偶尔还能看到 `graph-test-<pid>/`(进程内已确认删空,是本机沙箱在进程退出后把删除路径又放回来了,与测试代码无关)。一条命令清掉:
|
|
|
|
|
|
|
|
|
|
|
|
rm -rf "E:/ProgramData/AIProject/ai1net-dsh-server/tmp"/graph-test-*
|
|
|
|
|
|
|
|
|
|
|
|
八个用例类各管一摊:
|
|
|
|
|
|
|
|
|
|
|
|
1、`T1_Init` —— 建图:`--kpi` 按条数生成节点(全角分号也认)、`--nodes-json` 带依赖与域、重复 id 报错、自动编号避让、`max_parallel`。
|
|
|
|
|
|
2、`T2_CheckErrors` —— 硬错三条:环(含自环)、依赖指向不存在的节点、状态非法。
|
|
|
|
|
|
3、`T3_CheckWarnings` —— 警告三类:无域、无判据、域重叠(`docs/` 与 `docs/ui/` 双向都算)。
|
|
|
|
|
|
4、`T4_Ready` —— 就绪集:依赖未满足、域与在跑冲突、超 `max_parallel`(running 占名额)、两个域重叠的节点不进同一批。
|
|
|
|
|
|
5、`T5_Flow` —— 流转:`pending→running→done`、`events.jsonl` 只追加、`blocked` 累加 `attempts`、回报后回带 `next_ready`。
|
|
|
|
|
|
6、`T6_Illegal` —— 非法操作:`running`/`done` 再 `start` 拒绝,`blocked` 可重开;`--state` 只认 `done` / `blocked`;不存在的节点/图报错。
|
|
|
|
|
|
7、`T7_Edge` —— 边界:单节点图、空节点图、gid 含中文(显式与自动生成各一条)、`list` 统计与空工作区。
|
|
|
|
|
|
8、`T8_Isolation` —— 独立性:工作区里预埋的 `goal.json` / `tasks.json` / `collabd-state.json` 跑完字节不变,且不新建这类文件,写入范围只有 `<ws>/.workbuddy/graph/`。
|
|
|
|
|
|
|
|
|
|
|
|
测试对 `graphctl.py` 的唯一要求是「能当命令行跑」,不 import 它的内部函数 —— 所以改内部实现不会连带改测试。
|
|
|
|
|
|
|
|
|
|
|
|
## 六、还没做的(下一步)
|
2026-10-18 22:28:28 +08:00
|
|
|
|
|
|
|
|
|
|
- 自动派活:读 `ready` 后自动建排期(要复用现有排期硬规则:cwds 正斜杠、workspace_scope、next_run_at 毫秒、scheduled_at ISO)。
|
|
|
|
|
|
- 判定节点完成:现在靠回报 `--state done`,还没有「看证据够不够」的自动判定。
|
|
|
|
|
|
- 回退边:`attempts` 已经在记,还没有「判不过回到哪个节点」的字段与规则。
|
|
|
|
|
|
|
|
|
|
|
|
这三件都只在本目录内加,不影响现有机制。
|