From 254a03a821ef4e80af7ae1b6e11542fce881b4c1 Mon Sep 17 00:00:00 2001 From: cfdaily Date: Mon, 18 May 2026 10:52:32 +0800 Subject: [PATCH] auto-sync: 2026-05-18 10:52:32 --- .../v2.7-three-tier-hierarchy.md | 0 docs/design/v2.7-subtask-model.md | 518 +++++++++--------- 2 files changed, 261 insertions(+), 257 deletions(-) rename docs/design/{ => archive}/v2.7-three-tier-hierarchy.md (100%) diff --git a/docs/design/v2.7-three-tier-hierarchy.md b/docs/design/archive/v2.7-three-tier-hierarchy.md similarity index 100% rename from docs/design/v2.7-three-tier-hierarchy.md rename to docs/design/archive/v2.7-three-tier-hierarchy.md diff --git a/docs/design/v2.7-subtask-model.md b/docs/design/v2.7-subtask-model.md index 6a4e817..90fd0db 100644 --- a/docs/design/v2.7-subtask-model.md +++ b/docs/design/v2.7-subtask-model.md @@ -1,326 +1,330 @@ -# v2.7 数据模型重新设计:Project → Task → SubTask +# v2.7 数据模型设计:Project → Task → SubTask > 日期:2026-05-18 -> 版本:v1.0(基于 2026-05-18 08:13 ~ 08:21 讨论定稿) +> 版本:v2.0(经 08:02 ~ 10:50 讨论定稿) > 作者:庞统 -> 状态:待确认 -> 前置:回滚 v2.7 Card 层(设计文档 + 代码) +> 状态:待评审 +> 司马懿意见:Mail #302(背靠背讨论)、Mail #297(结论一致) --- -## 一、概念对齐 +## 一、设计推导过程 -| 层级 | 语义 | 例子 | 谁创建 | 生命周期 | -|------|------|------|--------|---------| -| **Project** | 仓库/组织 | sanguo_quant_live、sanguo_vnpy | 系统(自动发现)+ 用户 | 长期 | -| **Task** | 用户的一条需求/意图/目标 | "动量策略v1"、"下载分钟线"、"v2.7开发" | 用户 / AI | 天~周 | -| **SubTask** | Agent 领走执行的原子动作 | 张飞编码、赵云备数据、司马懿评审 | AI(庞统分解)| 小时~天 | +### 1.1 起因:Card 层为什么被回滚 -### 关键认知 +v2.7 原设计是 `Project → Card → Task` 三级层次结构。经过讨论发现 Card 是一个位置尴尬的中间层: -1. **Task 是用户视角的最小单位**:用户说"帮我做动量策略v1",这就是一个 Task -2. **SubTask 是 Agent 视角的最小单位**:庞统把 Task 拆解后分发给各将军 -3. **SubTask 可以跨 Project**:姜维在 sanguo_vnpy 搭回测引擎,服务的是 sanguo_quant_live 的 Task -4. **SubTask ≈ Stage**:同一个 Task 的 SubTask 按执行顺序形成 Stage 链 -5. **Task 间有依赖**:策略编码依赖数据准备,实盘依赖模拟验证 +| 概念 | 用户视角 | Card 层的位置 | +|------|---------|-------------| +| Project | 仓库/组织(sanguo_quant_live) | ✅ 一致 | +| Task | 用户的一条需求/目标("动量策略v1") | Card 吃掉了 Task 的语义 | +| 原子步骤 | Agent 执行的具体动作(张飞编码) | Card 下的 Task 才是真正的原子步骤 | ---- +**Card 既不是 Task(用户不会说"帮我建一个 Card"),也不是 SubTask(太粗了),更不是 Campaign(被锁在 Project 内)。** 它是一个多余抽象。 -## 二、回滚范围 +正确模型应该是用户自然使用的三层: -### 回滚 Card 相关代码(开发目录) - -| 文件 | 操作 | -|------|------| -| `src/blackboard/models.py` | 删除 Card 相关代码(CARD_VALID_STATUSES 等 + Card dataclass) | -| `src/blackboard/db.py` | 删除 `_CARDS_SCHEMA`、`_migrate_v27()`、cards 表 DDL;tasks 表移除 `card_id`、`stage` 列 | -| `src/blackboard/operations.py` | 删除 CardOps 类(create_card / list_cards / fork_card 等) | -| `src/blackboard/queries.py` | 移除 card_id 过滤参数 | -| `src/api/card_routes.py` | **删除整个文件** | -| `src/api/mail_routes.py` | **删除整个文件**(Mail 后续重新设计) | -| `src/blackboard/registry.py` | 保留 ProjectRegistry(不涉及 Card) | -| `src/daemon/ticker.py` | 移除 per-card 扫描逻辑,恢复 v2.6 per-project 扫描 | -| `src/main.py` | 移除 card_routes、mail_routes 注册;移除 v2.7 迁移调用 | -| `tests/test_v27_cards.py` | **删除整个文件** | - -### 回滚设计文档 - -| 文件 | 操作 | -|------|------| -| `docs/design/v2.7-three-tier-hierarchy.md` | 归档到 `docs/design/archive/` | - -### 保留 - -| 文件/功能 | 原因 | -|-----------|------| -| `registry.db` + ProjectRegistry + 自动发现 | Project 管理需要 | -| per-project `blackboard.db` | 多项目隔离需要 | -| Project API 路由 | 前端项目选择器需要 | -| Product 方向备忘录 | 新增,记录未来方向 | - ---- - -## 三、新增:SubTask 层 - -### 3.1 数据模型 - -**SubTask 表**(加到 per-project blackboard.db): - -```sql -CREATE TABLE IF NOT EXISTS subtasks ( - id TEXT PRIMARY KEY, -- 自动生成(如 st-a1b2c3) - task_id TEXT NOT NULL REFERENCES tasks(id), -- 所属 Task - title TEXT NOT NULL, -- 如 "策略编码"、"数据清洗" - description TEXT DEFAULT '', - status TEXT NOT NULL DEFAULT 'pending' - CHECK (status IN ('pending','claimed','working','review','done','failed','blocked','cancelled')), - assignee TEXT, -- 执行 Agent(如 zhangfei-dev) - assigned_by TEXT, -- 分配者(通常是 pangtong-fujunshi) - stage TEXT DEFAULT NULL, -- 所属 Stage 标签(如 "research"、"coding") - stage_order INTEGER DEFAULT 0, -- Stage 内排序 - depends_on TEXT, -- JSON array of subtask ids(SubTask 间依赖) - output_summary TEXT DEFAULT NULL, -- 产出物摘要 - output_path TEXT DEFAULT NULL, -- 产出物路径 - parent_project TEXT DEFAULT NULL, -- 实际工作所在 Project(跨项目时用) - retry_count INTEGER NOT NULL DEFAULT 0, - max_retries INTEGER NOT NULL DEFAULT 2, - created_at TEXT NOT NULL DEFAULT (datetime('now')), - updated_at TEXT NOT NULL DEFAULT (datetime('now')), - started_at TEXT, - completed_at TEXT -); -CREATE INDEX IF NOT EXISTS idx_subtasks_task ON subtasks(task_id); -CREATE INDEX IF NOT EXISTS idx_subtasks_status ON subtasks(status); -CREATE INDEX IF NOT EXISTS idx_subtasks_assignee ON subtasks(assignee); -CREATE INDEX IF NOT EXISTS idx_subtasks_stage ON subtasks(task_id, stage); +``` +Project(项目/仓库) + └── Task(用户需求/意图/目标) + └── SubTask(Agent 执行的原子任务/Stage) ``` -### 3.2 Task 表变更 +### 1.2 SubTask 表的讨论:为什么最终没建 -在现有 tasks 表基础上,新增字段: +**提出**:最初设计新建 `subtasks` 表,包含独立的状态、指派、依赖。 + +**质疑**: +1. **调度意义**:没有 SubTask 表也能调度——当前 Ticker 扫描 Task 就调度了。SubTask 作为调度单位的好处理论上是并行,但 Task 自引用(parent_task)已经能做到。 +2. **和已有设计的重叠**:v2.6 的 Task 表已有 `parent_task` 字段,拆解结果就是子 Task(Task 自引用)。课题4 的 planner.md 已定义了拆解流程(四步+组件库+PlanChecker)。新建 SubTask 表和这些重叠。 +3. **plan_json 也重叠**:已有 planner.md 模板指导庞统拆解,产出是黑板上的子 Task,不需要额外的 plan_json 字段。 + +**结论**:**不建 SubTask 表,复用 Task 自引用(parent_task)。** 子 Task 和父 Task 用同一张表,通过 `parent_task` 字段形成父子关系。 + +### 1.3 跨项目协作的讨论 + +**最初设计**:SubTask 级跨项目(姜维在 vnpy 为 quant_live 的某个 SubTask 工作)。 + +**修正**: +- 跨项目应该在 Task 级,不是 SubTask 级 +- 把 Task 整体信息(outputs、comments、黑板讨论)共享出去,具体用哪部分由 Agent 自己判断 +- 通过 bootstrap 注入实现(build_bootstrap 在 Agent 启动前把依赖 Task 的产出摘要拼装进 prompt) + +**结论**:Task 级跨项目,不改 API,通过 bootstrap 注入。 + +### 1.4 关系模型的讨论 + +任务之间存在三种可能的关系: + +| 关系 | 字段 | 语义 | 例子 | +|------|------|------|------| +| **父子** | `parent_task` | 组成归属——"我是谁的一部分" | 因子研究 **属于** 动量策略v1 | +| **依赖** | `depends_on` | 执行顺序——"我必须等谁完成" | 策略编码 **必须等** 因子研究完成 | +| **引用** | 新字段? | 成果物关联——"我用了谁的产出" | 动量策略v1 **用了** 回测引擎搭建的产出 | + +**背靠背讨论**(Mail #302 → #297): + +司马懿的独立判断: +- **父子**:有必要,提供聚合进度 + 前端分组。Card 回滚后 parent_task 是唯一的分组聚合手段 +- **依赖**:已确定必须保留,调度引擎消费 +- **引用**:当前没必要,没有消费者。和依赖有本质区别(依赖是调度的前置条件,引用是审计的溯源链),但当前审计场景不存在 +- **补充**:第三种关系可能是"模板/实例"(多个策略用相同 stages 流程),但 stages_json 已能表达 + +**最终结论**: + +| 字段 | 保留 | 用途 | +|------|------|------| +| `parent_task` | ✅ | 聚合进度 + 前端分组 | +| `depends_on` | ✅ | 调度顺序 | +| 引用 | ❌ | 未来按需加 `references TEXT` | +| `stages_json` | ✅ 新增 | 动态 Stage 定义 | + +### 1.5 状态的讨论 + +**最初提出** `planning` / `challenging` 两个新状态。 + +**修正**:课题3 已定义了完整的审查流水线(plan_review / output_review / guardrail / final_review),课题4 已定义了拆解流程。不需要额外加这两个状态。 + +**结论**:不加新状态,复用已有机制。 + +### 1.6 前端展示的讨论 + +**Stage 进度条**:和当前的固化 5 阶段(pending→claimed→working→review→done)一个意思,只是变成动态的 stages_json 定义的阶段。 + +**百分比问题**:Stage 是动态的,后续节点还没执行到,百分比不可靠。改用 `■■□□□ 2/5` + 当前 Stage 名。 + +--- + +## 二、最终设计 + +### 2.1 数据模型 + +**不建新表,只改现有 Task 表:** ```sql -ALTER TABLE tasks ADD COLUMN stages_json TEXT DEFAULT '[]'; -- Stage 定义(AI 生成) -ALTER TABLE tasks ADD COLUMN plan_json TEXT DEFAULT NULL; -- 完整分解计划(庞统生成) +-- 新增字段 +ALTER TABLE tasks ADD COLUMN stages_json TEXT DEFAULT '[]'; ``` -**`stages_json` 格式**: +**stages_json 格式**: ```json [ {"id": "research", "label": "因子研究", "order": 1}, {"id": "data_prep", "label": "数据准备", "order": 2}, {"id": "coding", "label": "策略编码", "order": 3}, - {"id": "backtest", "label": "历史回测", "order": 4}, + {"id": "backtest", "label": "回测验证", "order": 4}, {"id": "optimize", "label": "参数优化", "order": 5} ] ``` -**`plan_json` 格式**: - -```json -{ - "version": 1, - "created_by": "pangtong-fujunshi", - "created_at": "2026-05-18T08:00:00Z", - "stages": [...], - "subtasks": [ - { - "id": "st-001", - "title": "因子研究", - "assignee": "zhangfei-dev", - "stage": "research", - "depends_on": [], - "parent_project": null - }, - { - "id": "st-002", - "title": "分钟线数据下载", - "assignee": "zhaoyun-data", - "stage": "data_prep", - "depends_on": [], - "parent_project": null - }, - { - "id": "st-003", - "title": "策略编码", - "assignee": "zhangfei-dev", - "stage": "coding", - "depends_on": ["st-001", "st-002"], - "parent_project": null - }, - { - "id": "st-004", - "title": "回测引擎搭建", - "assignee": "jiangwei-infra", - "stage": "backtest", - "depends_on": [], - "parent_project": "sanguo_vnpy" - } - ] -} -``` - -### 3.3 跨项目 SubTask - -**`parent_project` 字段**: - -- `NULL`:SubTask 在当前 Project 内执行 -- `"sanguo_vnpy"`:SubTask 实际工作在另一个 Project 目录 - -跨项目 SubTask 的执行流程: -1. 庞统在 Task A(sanguo_quant_live)分解时,识别到需要回测引擎 -2. 创建 SubTask st-004,`parent_project=sanguo_vnpy` -3. Ticker 在 sanguo_vnpy 项目也扫描到这个 SubTask(通过 cross-project 查询) -4. 姜维在 sanguo_vnpy 执行完成后,结果写回 Task A 的 SubTask - -**注意**:跨项目执行是复杂场景,v2.7 先做数据模型支持(字段存在),执行逻辑后续迭代。 - -### 3.4 现有表关联 SubTask - -以下表新增 `subtask_id` 字段(可选,向后兼容): +**父子关系**(已有字段,启用使用): ```sql -ALTER TABLE events ADD COLUMN subtask_id TEXT; -ALTER TABLE comments ADD COLUMN subtask_id TEXT; -ALTER TABLE outputs ADD COLUMN subtask_id TEXT; -ALTER TABLE task_attempts ADD COLUMN subtask_id TEXT; +-- 已存在,不需要 ALTER +parent_task TEXT -- 子 Task 填父 Task 的 id,顶层 Task 为 NULL ``` -这样 Events、Comments、Outputs 既可以关联到 Task 级别,也可以精确到 SubTask 级别。 +**关系总结**: ---- +| 字段 | 语义 | 消费者 | +|------|------|--------| +| `parent_task` | 组成归属 | 前端分组、进度聚合 | +| `depends_on` | 执行顺序 | Ticker 调度引擎 | +| `stages_json` | 动态阶段定义(仅顶层 Task) | 前端 Stage 进度展示 | -## 四、Task 状态 = SubTask 状态聚合 +### 2.2 父子关系行为规则 -Task 不独立维护复杂状态机,核心状态从 SubTask 推导(类似之前 Card 的聚合逻辑,但语义更自然): +**子 Task 创建**: +- 庞统拆解时,为每个原子步骤创建子 Task(`parent_task=父Task.id`) +- 子 Task 有自己独立的 `status`、`assignee`、`depends_on`、`stage` +- 子 Task 的 `stage` 字段绑定到父 Task 的 `stages_json` 中的某个 stage id -| Task 状态 | 推导规则 | -|-----------|---------| -| `pending` | 所有 SubTask 都是 pending,或无 SubTask | -| `working` | 有 SubTask 在 working | -| `review` | 有 SubTask 在 review | -| `done` | 所有 SubTask 都是 done | -| `failed` | 有 SubTask failed 且无 active SubTask | -| `blocked` | 有 SubTask blocked 且无 active SubTask | +**父 Task 状态 = 子 Task 聚合**: + +| 父 Task 状态 | 推导规则 | +|-------------|---------| +| `pending` | 所有子 Task 都是 pending,或无子 Task | +| `working` | 有子 Task 在 working/claimed | +| `review` | 有子 Task 在 review | +| `done` | 所有子 Task 都是 done | +| `failed` | 有子 Task failed 且无 active 子 Task | +| `blocked` | 有子 Task blocked 且无 active 子 Task | | `cancelled` | 用户/AI 取消(手动设置) | -**额外状态**(不属于聚合,手动设置): -- `planning`:庞统正在分解 Task(生成 plan_json) -- `challenging`:司马懿正在审核分解方案 +**聚合刷新时机**:每次 Ticker tick 时,扫描有子 Task 的父 Task,刷新聚合状态。 ---- - -## 五、API 路由 - -### 5.1 Task 级(已有,微调) +### 2.3 示例数据 ``` -GET /api/projects/{pid}/tasks → Task 列表(含 SubTask 聚合状态) -POST /api/projects/{pid}/tasks → 创建 Task(用户需求) -GET /api/projects/{pid}/tasks/{tid} → Task 详情 + Stage 进度 -PATCH /api/projects/{pid}/tasks/{tid} → 更新 Task(如取消、改优先级) -DELETE /api/projects/{pid}/tasks/{tid} → 删除 Task +tasks 表: + +| id | title | parent_task | depends_on | stage | status | assignee | +|-----------|-------------|-------------|---------------|-----------|---------|-----------| +| task-001 | 动量策略v1 | NULL | NULL | NULL | working | NULL | ← 父 Task +| task-002 | 因子研究 | task-001 | [] | research | done | zhangfei | ← 子 Task +| task-003 | 分钟线下载 | task-001 | [] | data_prep | done | zhaoyun | ← 子 Task +| task-004 | 策略编码 | task-001 | [task-002,task-003] | coding | working | zhangfei | ← 子 Task +| task-005 | 回测验证 | task-001 | [task-004] | backtest | pending | NULL | ← 子 Task + +task-001 的 stages_json: +[{"id":"research","label":"因子研究","order":1}, + {"id":"data_prep","label":"数据准备","order":2}, + {"id":"coding","label":"策略编码","order":3}, + {"id":"backtest","label":"回测验证","order":4}, + {"id":"optimize","label":"参数优化","order":5}] ``` -### 5.2 SubTask 级(新增) +### 2.4 跨项目协作 -``` -GET /api/projects/{pid}/tasks/{tid}/subtasks → Task 下所有 SubTask(按 Stage 分组) -POST /api/projects/{pid}/tasks/{tid}/subtasks → 创建 SubTask(AI/手动) -GET /api/projects/{pid}/tasks/{tid}/subtasks/{stid} → SubTask 详情 -PATCH /api/projects/{pid}/tasks/{tid}/subtasks/{stid} → 更新 SubTask(状态、指派) -POST /api/projects/{pid}/tasks/{tid}/subtasks/{stid}/status → 更新状态(Agent 回调) -POST /api/projects/{pid}/tasks/{tid}/subtasks/{stid}/outputs → 提交产出 -``` +**方式**:通过 bootstrap 注入(不改 API)。 -### 5.3 便利路由 +`build_bootstrap()` 在 spawn Agent 前: +1. 查黑板找到依赖 Task 的 outputs 和 comments +2. 拼装到 Agent 的 prompt 里 +3. Agent 开箱就能看到依赖信息,不需要自己跨项目查询 -``` -GET /api/projects/{pid}/tasks/{tid}/progress → Stage 进度条数据 -GET /api/projects/{pid}/subtasks → 项目级所有 SubTask(跨 Task 查询) -``` +### 2.5 Ticker 变更 -### 5.4 向后兼容 - -- 旧路由 `/api/projects/{pid}/tasks` 保留 -- 不传 SubTask 相关参数时行为不变 -- Task 的 status 仍然可用(聚合推导) - ---- - -## 六、Ticker 变更 - -### 6.1 扫描逻辑 +**和 v2.6 基本一致,只加两步**: ```python -for project in registry.list_projects(status='active'): - db_path = data_root / project.id / "blackboard.db" - tasks = queries.tasks_by_status(db_path, ['pending', 'working', 'planning']) - for task in tasks: - # 1. 如果 Task 在 planning → 触发庞统分解 - if task.status == 'planning': - dispatch_planning(task) - continue - # 2. 扫描 Task 下 pending 的 SubTask - pending = queries.pending_subtasks(db_path, task.id) - for subtask in pending: - if deps_satisfied(subtask): - dispatch_subtask(subtask) - # 3. 聚合刷新 Task 状态 - refresh_task_status(db_path, task.id) +async def _tick_project(self, project_id, project_info): + # 1. 扫描当前状态(不变) + # 2. 依赖推进(不变) + # 3. 僵尸/超时处理(不变) + # 4. 调度 pending 子 Task(不变——和调度普通 Task 一样) + # 5. 调度审查(不变) + # 6. 【新增】聚合父 Task 状态 + refresh_parent_task_statuses(db_path) + # 7. 写 daemon_tick 事件(不变) ``` -### 6.2 调度粒度 +**调度逻辑完全不变**——子 Task 和普通 Task 一样被扫描、调度。唯一的变更是 tick 末尾加一步聚合刷新。 -- **调度单位**:SubTask(不是 Task) -- **状态聚合**:每次 tick 刷新 Task 的聚合状态 -- **max_dispatch_per_tick**:全局限制(恢复 v2.6 语义) +### 2.6 前端改动 + +#### 2.6.1 Task 看板(EdictBoard.tsx) + +- 任务列表只显示**顶层 Task**(`parent_task IS NULL`) +- Task 卡片新增: + - `■■□□□ 2/5`(已完成子 Task 数 / 总子 Task 数) + - `当前:策略编码`(当前活跃子 Task 的 stage label) + +#### 2.6.2 Task 详情弹窗(TaskModal.tsx) + +- **Stage 进度条**:从 `stages_json` 读取,按子 Task 状态标记每个 Stage(✅ done / 🔄 working / ⬜ pending) +- **子 Task 列表**:按 Stage 分组展示,每个子 Task 显示标题、Agent、状态、产出 +- 和现有的进度条 + 实时动态是一个意思,只是从固化的 5 阶段变成动态 Stage + +#### 2.6.3 Mail Tab + +- 新增 Tab,列表展示 Sanguo Mail +- 后续独立实现 + +#### 2.6.4 不做的 + +- 不做独立的 SubTask 管理页 +- 不做跨 Project 的 Product 视图 +- 不做 Card 看板 --- -## 七、前端改动(最小) +## 三、回滚范围 -### 7.1 不改的 +### 3.1 代码回滚(开发目录 `~/.openclaw/sanguo_projects/sanguo_moziplus_v2/`) -- 整体布局不变(Tab 栏 + 内容区) -- 项目选择器保持下拉菜单 -- EdictBoard(Task 看板)基本不变 +| 文件 | 操作 | +|------|------| +| `src/blackboard/models.py` | 删除 Card dataclass + CARD_VALID_STATUSES + CARD_TYPE_SET + CARD_MANUAL_STATUSES | +| `src/blackboard/db.py` | 删除 `_CARDS_SCHEMA`、`_migrate_v27()`;tasks DDL 移除 `card_id`、`stage`;保留其他所有内容 | +| `src/blackboard/operations.py` | 删除 CardOps 类全部方法 | +| `src/blackboard/queries.py` | 移除 card_id 过滤参数 | +| `src/api/card_routes.py` | **删除整个文件** | +| `src/api/mail_routes.py` | **删除整个文件** | +| `src/daemon/ticker.py` | 移除 per-card 扫描逻辑(`_tick_card`、`CardOps` 引用),恢复 per-project 直扫 | +| `src/main.py` | 移除 card_routes、mail_routes 注册;移除 v2.7 迁移调用;版本号保持 2.7.0 | +| `tests/test_v27_cards.py` | **删除整个文件** | -### 7.2 改的 +### 3.2 设计文档 -1. **Task 详情弹窗(TaskModal.tsx)**: - - 新增 Stage 进度条(从 stages_json 读取) - - SubTask 列表(按 Stage 分组) - - 每个 SubTask 显示:标题、Agent、状态、产出 +| 文件 | 操作 | +|------|------| +| `docs/design/v2.7-three-tier-hierarchy.md` | 移至 `docs/design/archive/` | -2. **Task 看板卡片**: - - 加 Stage 进度指示器(小进度条) +### 3.3 保留 -3. **Mail Tab**(后续独立实现): - - 新增 Tab,列表展示 Sanguo Mail - -### 7.3 暂不做的 - -- 独立的 SubTask 看板/管理页面 -- 跨 Project 的 Product 视图 -- Card 看板 +| 文件/功能 | 原因 | +|-----------|------| +| `registry.db` + ProjectRegistry + 自动发现 | Project 管理需要 | +| per-project `blackboard.db` | 多项目隔离需要 | +| Project API 路由 | 前端项目选择器需要 | +| `docs/design/product-direction-notes.md` | 新增,Product 方向备忘 | --- -## 八、实施计划 +## 四、新增内容 -| 序号 | 任务 | 预计 | +### 4.1 后端 + +| 序号 | 任务 | 文件 | 说明 | +|------|------|------|------| +| 1 | tasks DDL 加 `stages_json` | `db.py` | `ALTER TABLE tasks ADD COLUMN stages_json TEXT DEFAULT '[]'` | +| 2 | 子 Task 聚合函数 | `operations.py` | `refresh_parent_status(db_path, parent_task_id)` | +| 3 | 按 parent_task 查询 | `queries.py` | `list_subtasks(db_path, parent_task_id)` | +| 4 | Ticker 加聚合刷新 | `ticker.py` | tick 末尾调用聚合函数 | +| 5 | API 路由微调 | `blackboard_routes.py` | Task 详情接口返回子 Task 列表 + Stage 进度 | + +### 4.2 前端 + +| 序号 | 任务 | 文件 | 说明 | +|------|------|------|------| +| 6 | Task 卡片加进度指示 | `EdictBoard.tsx` | `■■□□□ 2/5` + 当前 Stage 名 | +| 7 | Task 详情弹窗改造 | `TaskModal.tsx` | 动态 Stage 进度条 + 子 Task 列表 | +| 8 | store/api 适配 | `store.ts` + `api.ts` | 加载子 Task 数据、Stage 进度 | + +### 4.3 测试 + +| 序号 | 任务 | 文件 | |------|------|------| -| 1 | 回滚 Card 层(代码 + 设计文档归档) | 2h | -| 2 | 新增 SubTask 表 + models + operations | 3h | -| 3 | Task 表加 stages_json/plan_json + 聚合状态 | 2h | -| 4 | SubTask API 路由 | 2h | -| 5 | Ticker 适配(per-SubTask 调度 + 状态聚合) | 2h | -| 6 | 前端 Task 详情弹窗改造(Stage 进度 + SubTask 列表) | 3h | -| 7 | 测试 + 司马懿评审 | 2h | -| **合计** | | **~16h** | +| 9 | 子 Task CRUD + 聚合 | `test_v27_subtasks.py` | +| 10 | 现有测试不回归 | 全量 pytest | -### 优先级 +--- -先回滚(1)→ 再建 SubTask(2-5)→ 前端(6)→ 评审测试(7) +## 五、实施顺序 + +| 阶段 | 任务 | 预计 | +|------|------|------| +| **Phase 1:回滚** | 删除 Card 层代码 + 归档设计文档 | 2h | +| **Phase 2:后端** | stages_json + 聚合 + 查询 + Ticker + API | 4h | +| **Phase 3:前端** | 卡片指示器 + 详情弹窗改造 | 4h | +| **Phase 4:测试** | 新测试 + 全量回归 | 2h | +| **Phase 5:评审** | 发司马懿评审 + 修复 | 2h | +| **合计** | | **~14h** | + +--- + +## 六、Product 方向备忘(不实施,记录未来) + +详见 `docs/design/product-direction-notes.md`。 + +核心思路:Product = 跨 Project 的 Task 聚合,多个 Task 的产出物组合成完整产品。和 Project 是正交维度。等有实际场景再建模。 + +--- + +## 七、讨论参与 + +| 时间 | 参与者 | 内容 | +|------|--------|------| +| 08:02 | 用户 | 质疑 Card 层存在必要性,提出 Project → Task → SubTask 三层 | +| 08:07 | 用户 | 提出 Campaign/Product 概念(跨项目 Task 聚合) | +| 08:13 | 用户 | 确认四层:Project → Task → SubTask → Product(未来),决定回滚 Card | +| 08:21 | 用户 | 确认三条:回滚 Card、完善三层、记录 Product 方向 | +| 08:47 | 用户 | 追问 SubTask 表用途、parent_project 归属、plan_json 重叠、状态必要性 | +| 09:55 | 用户 | 确认 Task 级跨项目、不需要 planning/challenging 状态、追问 bootstrap 注入含义 | +| 09:59 | 用户 | 确认进度展示方式,追问 parent_task 含义 | +| 10:00 | 用户 | 追问父子 vs 引用 vs 依赖的业务选择 | +| 10:03 | 用户 | 要求背靠背发给司马懿讨论 | +| 10:10 | 司马懿 | 回复:留父子+依赖,砍引用,补充模板/实例关系 | +| 10:50 | 用户 | 确认最终方案,要求更新设计文档并统一发评审 |