# 构想: 任务推进全局设计（AI-First 推进链） — 2026-06-14

> 性质: 架构设计 / 实现方案
> 关联: df-workflow · AiNode/HumanNode · knowledge 状态机范式 · devflow AI-First 定位（kms/devflow_ai_first_model.html）
> 修订:
> - 多角度对抗论证收敛（kind/状态机不抽层/范围精简）
> - 对抗性验证升级（5 维度：收口/并发/崩溃/一致性/前端）
> - **AI-First 定位确认**：任务由 AI 执行→AI 自审→人工最终核对（人从操作者转为审批者）

---

## 定位：AI-First 推进链（核心转向）

devflow 是 AI-First 工具。任务推进**不是人点按钮的操作流，是 AI 的执行流**：

```
todo ──AI执行──▶ in_progress ──AI自审──▶ review_ready ──人工核对──▶ done
       AiNode            AiNode              HumanNode
       AI 干活          AI 审 AI 的活        人最终把关 AI 产出
```

- **AI 执行**：任务内容由 AI 干（写代码、改文件、跑测试）。干完自动推进，人不必手动点「开始」。
- **AI 自审**：AI 审 AI 自己的产出（code review，结构化结论）。审过推进，审出问题退回重做。
- **人工最终核对**：人在 merge 关卡最终把关 AI 产出。**这是 AI-First 的核心契约——人监督 AI**，不是人确认自己的活。

**advance_task 的默认触发者从「人」变成「AI」**（执行/自审完成事件触发），人可介入/覆盖/微调。人从「操作者」转为「审批者」。

### 这修复了对抗验证的 merge 零因果批评

对抗验证 Agent 4 批评「单人场景 merge 审批零因果——自审自批≈手切」。**AI 执行 + 人工核对**正好修复：merge 不再是人确认自己的活，而是**人监督 AI 的活**——从形式主义升级为实质关卡。

---

## 背景

项目管理任务维护目前**只能创建，不能推进**——前端状态标签纯展示无入口。根因缺「推进编排层」：状态字段、工作流引擎、分支表、状态机范式各干各的，且**完全缺 AI 执行层**。

## 痛点

| 已有能力 | 位置 | 现状 |
|---|---|---|
| 任务状态字段（裸 String，无值域校验） | `models.rs:52` | 无状态机、无联动、前端不暴露 |
| 工作流引擎（ScriptNode/HumanNode/**AiNode**） | `df-workflow/*` + `df-nodes/*` | 三种节点现成，AiNode 注释明示设计意图「AI 分析→人工审批」，但推进链没用上 |
| 分支表状态 | `models.rs:69` | 语义同构，未联动 |
| 状态机范式 | `knowledge.rs:53` | 只在 knowledge 用 |
| **AI 执行能力** | `df-ai` provider + `ai_node.rs` | AiNode 通用 LLM 调用现成；agent 级「写代码改文件」能力渐进 |

---

## 核心模型：AI-First 推进链 + 状态机

### 状态机（AI 推进 + 退回 + 旁路）

```
        AI执行闸门              AI自审闸门           人工核对闸门
todo ───────────▶ in_progress ──────────▶ review_ready ──────────▶ done
                      ▲                       │ │
                      └── AI自审block/人工拒绝 ┘ │  (AI 重做)
                                               ▼
                                          abandoned (任意态可放弃,终态不可逆)
```

**退回边** `review_ready → in_progress`：AI 自审 block 或人工拒绝 → 退回让 AI 重做。AI 推进下退回比人推进更频繁（AI 反复审自己），故 loop 管理必要。

### 闸门策略（三闸门各司其职，都必需）

| 边 | 闸门 | 节点 | 阶段一 | 阶段二 |
|---|---|---|---|---|
| `start` | **AI 执行** | AiNode/agent | ✅ 必需（最小形态） | + git worktree（code kind） |
| `ready` | **AI 自审** | AiNode | ✅ 必需 | + lint/test 真校验 |
| `merge` | **人工核对** | HumanNode | ✅ 必需（人监督 AI） | + git merge 副作用 |
| `abandon` | 无 | — | 直接转 | 直接转 |

三闸门都必需（不再是「merge 强制 + start/ready 关闭」）——AI 推进链上每环都有节点把关。

### ⚠️ 失败路径定义（含 AI 执行/自审失败）

| 失败场景 | 工作流结果 | 任务状态 | 反馈 |
|---|---|---|---|
| **AI 执行失败**（agent 报错/超时） | failed | 保持 todo | 「AI 执行失败：<错误>」，人可重试或介入手干 |
| **AI 自审 block**（审出严重问题） | failed | **退回 in_progress**（AI 重做） | 「AI 自审未通过：<问题清单>」 |
| **AI 自审 warn**（轻微问题） | completed（带警告） | 推进到 review_ready | 警告附在任务上，人核对时可见 |
| **人工拒绝** | failed | **退回 in_progress**（AI 重做） | 「人工核对未通过：<意见>」 |
| **闸门脚本失败**（阶段二 lint/test） | failed | 保持推进前 | 「闸门失败」 |
| **审批超时/取消** | failed/Err | 保持推进前 | 「超时/已取消」 |
| **应用崩溃** | running 孤儿 | 保持推进前，可重新推进 | 启动提示「检测到中断的推进」 |

**关键**：AI 自审/人工核对的「拒绝/block」→ 退回 in_progress 让 AI 重做（不是退回给人干——AI-First 下人是审批者不是执行者）。

### AI 自审结果处理（建议性 vs 强制）

AiNode 输出纯文本，要判通过与否得约定结构化输出 + 解析：

```json
{ "verdict": "pass" | "warn" | "block", "issues": [...], "summary": "..." }
```

- `pass`：推进；`warn`：推进但带警告；`block`：退回 in_progress
- 默认 AI 自审走 verdict 判定（非纯建议），否则 AI 推进链断在人审前
- 人审（merge）仍是最终关卡，可覆盖 AI 自审结论

---

## AI 执行层（新增，核心缺口）

任务内容由谁干——这是原方案的最大盲区。AI-First 下由 AI 执行。

### 实现形态

- **AiNode/agent 执行**：start 闸门触发 AiNode（或更复杂的 agent 编排）干活——读任务描述 + 项目上下文 → 写代码/改文件/跑测试 → 产出 diff
- **执行能力渐进**：阶段一最小形态（AiNode 跑执行 prompt / 接现有 AI 工具链），阶段二+ 逐步增强（agent 多步、文件操作、git worktree 内执行）
- **执行产出**：代码 diff / 文件变更 / 测试结果，供下游 AI 自审节点消费

### advance_task 触发者变更

- **默认**：AI 执行完成事件 → 自动触发 advance_task(start→推进)
- AI 自审完成 → 触发 advance_task(ready→推进或退回)
- 人工核对完成 → 触发 advance_task(merge→done)
- **人可介入**：任何节点人能手动推进/覆盖/接手（人转手干）

---

## 【P0】状态机收口（对抗验证最高优先级）

### 致命漏洞：update_task 是公开旁路

`task.rs:74` update_task 白名单含 `"status"`（`crud.rs:291`），任意调用方一行绕过所有闸门和状态机。且 `crud tests:249` 单测固化旁路。AI 推进下更危险——AI agent 若能调 update_task 改 status，整个 AI 执行/自审/核对链形同虚设。

### 收口措施

1. 从 tasks 白名单**移除 `"status"`**
2. **advance_task 成为 status 唯一写入路径**（AI 触发也走它）
3. 删除/改写 `update_field_allows_tasks_status` 单测
4. advance_task 内联 `validate_task_status` 值域校验

---

## 状态集清理（非「定稿」）

对抗验证纠误：前端早已 5 态，后端 enum 多 3 个僵尸死状态（InReview/Testing/Blocked 零使用）。是「清理僵尸」非「7→5 定稿」。

措施：删后端 enum 死状态 + `merged→done` 改名 + 迁移前抽样 + status 值域校验。

```sql
-- 迁移（幂等，conn.transaction() 包裹）
UPDATE tasks SET status='done' WHERE status='merged';
```

---

## 任务类型：阶段一不加 kind

对抗验证：阶段一 code/generic 行为零差异，违反 YAGNI。阶段二 git 联动需要区分时再加 kind（ALTER + 回填 generic）。`tags` 保留承担语义标注（doc/design）。

**AI 推进下的 kind 意义**：阶段二+ AI 执行内容按 kind 分化（code 任务 AI 写代码、doc 任务 AI 写文档、design 任务 AI 出图）。阶段一 AI 执行最小形态不区分，随能力增强再分。

---

## 状态机实现：不抽层 + 下沉 SQL

enum 补 `can_transition_to`（不新建 state_machine.rs，knowledge validate_transition 源码验证是空壳）：

```rust
impl TaskStatus {
  pub fn can_transition_to(&self, to: &TaskStatus) -> bool {
    match (self, to) {
      (Todo, InProgress | Abandoned) => true,
      (InProgress, ReviewReady | Abandoned) => true,
      (ReviewReady, Done | Abandoned | InProgress) => true, // 可退回（AI 重做）
      _ => false,
    }
  }
}
```

**状态机下沉 SQL**（TOCTOU 根治）：advance_task 的校验+写入合并为带前置条件的 UPDATE：

```sql
UPDATE tasks SET status=:new, updated_at=:now
WHERE id=:id AND status=:expected   -- affected_rows==0 即状态已变,拒绝
```

终态保护：`AND status NOT IN ('done','abandoned')`。

---

## loop 管理（AI 推进下必需）

AI 自审/人工核对退回 → AI 重做 → 再审 → 可能反复。加 `review_rounds: i32` 计数，退回时 +1：

- 任务卡显示「第 N 轮 review」（迭代可见性）
- 可选：轮数过高提示「是否卡住」（不强制终止——单人/AI 决定何时 done）
- 强制终止/阈值不做（over-engineering）

---

## 并发与一致性护栏（对抗验证新增）

AI 推进下并发更常见（多个任务并行 AI 执行）。护栏不变：

1. **per-task 互斥锁**：`task_locks: Arc<Mutex<HashMap<String, Arc<Mutex<()>>>>>`
2. **闸门工作流去重**：起 run_workflow 前查 running/interrupted 工作流
3. **WorkflowEvent 加 execution_id** + 转发过滤（防多任务事件串台）
4. **审批请求带 task_id**（task_id + execution_id + node_id 三元组）

---

## 数据一致性：跨表事务

`crud.rs` 无跨表事务，advance_task 多表写（task.status + workflow.status + 阶段二 branches/projects）半成品无法回滚。promote_idea 补偿范式不适用更新型。

措施：**补 `Database.transaction()`**（OwnedTransaction），advance_task 事务内提交。迁移幂等（column_exists + WHERE + conn.transaction 包裹）。tags 写入校验。

---

## 崩溃恢复（对抗验证新增，AI 推进下更关键）

AI 执行/自审是长时异步过程，崩溃恢复更关键：

1. **启动孤儿清理**：`UPDATE workflow_executions SET status='interrupted' WHERE status='running'`
2. **审批请求持久化**：HumanNode 阻塞前落库（node_executions status='pending'），启动恢复
3. **AI 执行状态持久化**：AI 执行（长时）需 checkpoint，崩溃后能恢复或安全重做（阶段二+）
4. **审批拒绝语义化**：HumanNode/AiNode 区分同意/拒绝/block，拒绝走失败路径不当 Ok
5. **重复触发守卫**：advance_task 入口检查 running/interrupted 工作流

---

## 前端改造（对抗验证新增 + AI 推进适配）

1. **pendingApprovals 数组化**（按 execution_id 索引）
2. **liveEvents 按 task 路由**：event payload 加 task_id，store 改 liveEventsByTask
3. **任务卡 AI 推进可视化**：显示当前在哪个环节（AI 执行中/AI 自审中/待人工核对/第 N 轮）
4. **按钮防重入**：advancingTaskIds: Set
5. **确认式更新**：等 IPC/workflow 事件再刷 task，非乐观更新
6. **AI 产出展示**：AI 执行的 diff、AI 自审的意见清单，供人核对时查看
7. **统一错误桥接**：全局 watch state.error → Message.error
8. **回调判定**：run_workflow 完成回调 advance_task 条件 `task_id.is_some()`

---

## 两阶段落地

### 阶段一：AI-First 推进链 + 工程护栏

**推进链**：
- 状态集清理（删僵尸 + merged→done）+ enum 补 can_transition_to
- **状态机收口**（移除 status 白名单 + advance_task 唯一入口 + 值域校验）← P0
- advance_task + 状态机下沉 SQL + on_task_advanced 空钩子
- **AI 执行闸门**（AiNode 最小形态）+ **AI 自审闸门**（AiNode 结构化 verdict）+ **人工核对闸门**（HumanNode）
- **失败路径定义**（AI 执行失败/AI 自审 block/人工拒绝→退回重做）
- **loop 管理**（review_rounds 计数）
- per-task 锁 + 闸门去重、跨表事务、WorkflowEvent 加 execution_id、启动孤儿清理 + 审批持久化
- WorkflowRecord 填值 + event payload 加 task_id
- 前端：pendingApprovals/liveEventsByTask/advancingTaskIds/确认式更新/AI 推进可视化

**触发者**：advance_task 支持 AI 事件触发 + 人手动介入双通道。

### 阶段二：Git + 联动 + AI 执行增强

- 加 kind 字段；code kind 闸门脚本换 git 命令串；start/ready 接真 git/lint/test
- AI 执行增强（agent 多步、worktree 内执行、文件操作）
- 填 on_task_advanced：分支联动 + 项目 completed（含边界守卫）
- BranchRecord 加 worktree_path

### Git 集成：直接外部命令

git 是 ScriptNode/AiNode 一串命令，不特殊化。不建 worktree.rs/df-git crate；不做 git 检测框架。硬依赖 git ≥2.20。非 code 任务不依赖 git。

### 联动策略

阶段一剥离分支联动和项目 completed（~90 行 + 边界漏洞），阶段二填钩子返工 <30 行。

---

## 落地改动点（阶段一，按优先级）

| 级 | # | 文件 | 改动 |
|---|---|---|---|
| **P0** | 1 | `crud.rs`+`task.rs` | 移除 status 白名单 + advance_task 唯一入口 + 值域校验 + 改单测 |
| **P0** | 2 | `task.rs` | advance_task + 状态机下沉 SQL + on_task_advanced 空钩子 + **支持 AI 事件触发** |
| **P0** | 3 | 闸门 DAG 模板 | **AI 执行（AiNode）+ AI 自审（AiNode verdict）+ 人工核对（HumanNode）三闸门** |
| **P0** | 4 | `human_node.rs`+`ai_node.rs`+`executor.rs` | **审批/自审拒绝语义化**（block/拒绝走失败路径不当 Ok） |
| **P1** | 5 | `task.rs`/`models.rs` | **review_rounds 计数**（退回 +1） |
| **P1** | 6 | `state.rs` | per-task 锁 + 闸门去重 |
| **P1** | 7 | `db.rs`/`crud.rs` | 补 Database.transaction() + 事务包裹 |
| **P1** | 8 | `events.rs`+`workflow.rs` | WorkflowEvent 加 execution_id + 转发过滤 |
| **P1** | 9 | `state.rs` init | 启动孤儿清理 + 审批持久化恢复 |
| **P1** | 10 | `types.rs` | 删 enum 僵尸 + 补 can_transition_to |
| **P1** | 11 | 迁移 | merged→done（幂等 + 事务）|
| **P1** | 12 | `workflow.rs` | run_workflow 加 task_id/project_id + event payload 加 task_id + 完成回调 |
| **P1** | 13 | `models.rs` | TaskRecord 加 tags（kind 推阶段二）+ review_rounds + 白名单 |
| **P1** | 14 | 前端 `project.ts`/vue | pendingApprovals 数组 + liveEventsByTask + advancingTaskIds + 确认式更新 + **AI 推进环节可视化** + **AI 产出/diff 展示** |
| **P2** | 15 | `constants`+i18n | merged→done 键名 + tags + review_rounds 文案 + AI 环节文案 |
| **P2** | 16 | `project.ts` | 全局 error 桥接 |

---

## 决策护栏（触发反转条件）

| 决策 | 反转条件 |
|---|---|
| AI-First 推进（AI 执行→自审→人核对） | AI 执行能力长期不足/不可靠 → 退回人执行 + AI 辅助审 |
| 阶段一不加 kind | 阶段二 doc/design 真要 AI 执行不同内容；或按 kind 统计 |
| 状态机不抽层 | 第三处状态机需统一审计 |
| 阶段一剥离联动 | 用户验收反馈「想看到项目自动完成」 |
| 不提前集成 git | worktree 异常恢复需 Rust 逻辑 |
| 状态机收口 | 出现「需批量脚本直接改 status」运维场景 → 另开受控入口 |
| AI 自审走 verdict 判定（非纯建议） | AI 自审误判率高 → 降级为建议性，人审全权 |

---

## 决策清单（人定取舍 · why）

| # | 决策 | 否决备选 | why |
|---|---|---|---|
| 1 | **AI-First 推进链**（AI 执行→AI 自审→人工核对） | 人点按钮推进 | devflow 是 AI-First 工具，任务是 AI 的执行流非人的操作流 |
| 2 | **advance_task 默认 AI 触发**，人可介入 | 仅人触发 | AI 执行/自审完成自动推进；人转审批者 |
| 3 | **AI 自审走 verdict 判定**（pass/warn/block） | 纯建议 | AI 推进链需 AI 自审能阻断，否则断在人审前 |
| 4 | **人工核对 = 人监督 AI**（非自审自批） | 人确认自己的活 | 修复 merge 零因果；AI-First 核心契约 |
| 5 | **拒绝/block → 退回 AI 重做**（非退回人干） | 退回人执行 | AI-First 下人是审批者不是执行者 |
| 6 | **loop 管理 review_rounds**（AI 推进必需） | 无计数 | AI 反复审自己，循环比人推进频繁 |
| 7 | 状态机收口（移除 update_task status） | 保留旁路 | 对抗验证：旁路让状态机形同虚设，AI 推进下更危险 |
| 8 | 阶段一不加 kind，阶段二再加 | 阶段一二分 | 对抗验证：阶段一零行为差异 |
| 9 | 状态机不抽层，enum 补方法 | 抽通用层 | 源码验证空壳 |
| 10 | 状态机下沉 SQL（WHERE 前置） | 纯内存校验 | 对抗验证：根治 TOCTOU |
| 11 | 失败路径全覆盖（含 AI 执行/自审失败） | 只描述快乐路径 | 对抗验证：拒绝被当成功是语义反转 |
| 12 | 补跨表事务 | 无事务多写 | 对抗验证：半成品无法回滚 |
| 13 | 崩溃恢复（孤儿清理+审批持久化+AI 执行 checkpoint） | 纯内存 | AI 执行长时异步，崩溃恢复更关键 |
| 14 | WorkflowEvent 加 execution_id | 全局单通道 | 对抗验证：多任务事件串台 |
| 15 | 状态集清理后端僵尸（非 7→5 定稿） | 当作待决策 | 对抗验证：前端早已 5 态 |
| 16 | 闸门三必需（AI执行/AI自审/人工核对） | merge 强制+其余关 | AI 推进链每环都有节点把关 |
| 17 | 阶段一剥离联动 | 顺带联动 | ~90 行+边界漏洞 |
| 18 | 预留 on_task_advanced 钩子 | 不预留 | 阶段二补是挂插件 |
| 19 | git=闸门脚本调外部命令 | worktree.rs/df-git crate | YAGNI |
| 20 | merged→done（迁移） | 文案分流 | 命名中性化 |
| 21 | 前端 pendingApprovals 数组 + 确认式更新 + AI 环节可视化 | 单值/乐观 | 对抗验证：多任务并发；AI 推进需环节可见 |

---

## 演进记录

1. **多角度论证收敛**：kind 二分、状态机不抽层、阶段一范围精简、闸门策略
2. **对抗性验证升级（5 维度）**：状态机收口/并发/崩溃恢复/一致性/前端——挖出 P0 致命项（旁路、审批拒绝=成功、TOCTOU、纯内存）
3. **AI-First 定位确认**：任务由 AI 执行→AI 自审→人工最终核对。补执行层（原方案最大盲区），advance_task 触发者改 AI，AI 审/loop 升必需，merge 升级为「人监督 AI」实质关卡
