chore(repo): reinitialize repository
This commit is contained in:
@@ -0,0 +1,790 @@
|
||||
# Inbox V2 数据库设计
|
||||
|
||||
本文档是 `inbox v2` 的数据库开发基线。
|
||||
|
||||
它服务于三件事:
|
||||
|
||||
1. 明确 `v2` 到底使用哪些数据库。
|
||||
2. 明确每张表的字段、主键、外键和作用。
|
||||
3. 明确各张表之间的关系,作为后续 `store / app / http` 实现依据。
|
||||
|
||||
## 1. 物理数据库
|
||||
|
||||
`v2` 先只使用 **1 个物理数据库**:
|
||||
|
||||
| 数据库 | 引擎 | 是否采用 | 用途 |
|
||||
| --- | --- | --- | --- |
|
||||
| `inbox.db` | SQLite | 是 | 所有运行时业务数据、在线可编辑配置、配置审计 |
|
||||
| Redis | - | 否 | 当前不需要单独缓存或队列 |
|
||||
| PostgreSQL | - | 否 | 当前先不引入额外运维复杂度 |
|
||||
| 独立日志库 | - | 否 | 执行日志先跟主库放一起 |
|
||||
| 向量库 | - | 否 | 当前主流程不依赖向量检索 |
|
||||
|
||||
一句话:
|
||||
|
||||
- `V2` 先只有一个库:`inbox.db`
|
||||
|
||||
## 2. 关键决策
|
||||
|
||||
### 2.1 配置入库
|
||||
|
||||
因为 `roles / prompts / skills / config` 需要满足:
|
||||
|
||||
- 前端可编辑
|
||||
- 保存后立即生效
|
||||
- 不需要改文件后再发版
|
||||
|
||||
所以第二版里,这些内容的**运行时真源就是数据库**。
|
||||
|
||||
文件只保留这些作用:
|
||||
|
||||
- 默认模板
|
||||
- 初始化导入源
|
||||
- 内置技能的原始资产
|
||||
|
||||
### 2.2 立即生效的定义
|
||||
|
||||
这里的“立即生效”定义为:
|
||||
|
||||
- 配置保存成功后
|
||||
- **下一次新的 agent run / 新的消息处理 / 新的 HTTP 请求** 立即读取最新配置
|
||||
|
||||
不包含:
|
||||
|
||||
- 已经运行中的 agent 进程半路热切换配置
|
||||
|
||||
### 2.3 配置覆盖规则
|
||||
|
||||
在线配置支持两层作用域:
|
||||
|
||||
1. `global`
|
||||
2. `workspace override`
|
||||
|
||||
解析优先级固定为:
|
||||
|
||||
`workspace row > global row`
|
||||
|
||||
也就是说:
|
||||
|
||||
- 如果某个 workspace 有自己的 prompt/config/binding,就优先使用它
|
||||
- 否则回退到全局默认
|
||||
|
||||
### 2.4 统一建模原则
|
||||
|
||||
1. 所有业务主键统一使用 `TEXT`
|
||||
2. 所有时间统一使用 UTC RFC3339
|
||||
3. 核心业务关系用结构化表,不用 JSON blob 代替
|
||||
4. JSON 只用于快照和弱结构扩展字段
|
||||
5. `topic` 是业务主实体
|
||||
6. `product` 接管需求整理文档
|
||||
7. `clarifier_state / clarifier_artifacts / topic_records` 在 `v2` 中不再保留
|
||||
|
||||
## 3. 数据域划分
|
||||
|
||||
| 数据域 | 表 |
|
||||
| --- | --- |
|
||||
| 系统 | `schema_migrations` |
|
||||
| 项目与工作区 | `projects`, `workspaces` |
|
||||
| 在线角色配置 | `roles`, `role_prompts`, `role_configs`, `skills`, `role_skill_bindings` |
|
||||
| Topic 与文档 | `topics`, `topic_documents` |
|
||||
| 消息协作 | `messages`, `message_deliveries` |
|
||||
| Requirement / Discovery / Workflow / Merge | `requirements`, `discovery_rounds`, `discovery_candidates`, `discovery_votes`, `workflow_runs`, `workflow_run_logs`, `merge_requests` |
|
||||
|
||||
## 4. 表清单总览
|
||||
|
||||
| 表名 | 数据域 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `schema_migrations` | 系统 | 迁移历史 |
|
||||
| `projects` | 项目 | 项目主表 |
|
||||
| `workspaces` | 工作区 | 工作区主表 |
|
||||
| `roles` | 在线角色配置 | 角色定义 |
|
||||
| `role_prompts` | 在线角色配置 | 角色提示词 |
|
||||
| `role_configs` | 在线角色配置 | 角色模型和运行配置 |
|
||||
| `skills` | 在线角色配置 | 技能定义 |
|
||||
| `role_skill_bindings` | 在线角色配置 | 角色与技能绑定 |
|
||||
| `topics` | Topic | 统一 topic 主实体 |
|
||||
| `topic_documents` | Topic | `PRD`、`Decision Log`、Discovery 文档 |
|
||||
| `messages` | 消息协作 | 消息信封与正文 |
|
||||
| `message_deliveries` | 消息协作 | 消息收件与归档状态 |
|
||||
| `requirements` | Requirement | pool 队列项 |
|
||||
| `discovery_rounds` | Discovery | discovery 轮次 |
|
||||
| `discovery_candidates` | Discovery | discovery 候选项 |
|
||||
| `discovery_votes` | Discovery | discovery 投票 |
|
||||
| `workflow_runs` | Workflow | 角色执行记录 |
|
||||
| `workflow_run_logs` | Workflow | 执行日志流 |
|
||||
| `merge_requests` | Merge | merge 请求记录 |
|
||||
|
||||
## 5. 表字段定义
|
||||
|
||||
### 5.1 `schema_migrations`
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `version` | `INTEGER` | PK | 迁移版本号 |
|
||||
| `name` | `TEXT` | NOT NULL | 迁移名称 |
|
||||
| `applied_at` | `TEXT` | NOT NULL | 执行时间 |
|
||||
|
||||
### 5.2 `projects`
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `id` | `TEXT` | PK | 项目 ID |
|
||||
| `slug` | `TEXT` | NOT NULL, UNIQUE | 项目标识 |
|
||||
| `name` | `TEXT` | NOT NULL | 展示名称 |
|
||||
| `root_path` | `TEXT` | NOT NULL, UNIQUE | 项目根目录 |
|
||||
| `default_branch` | `TEXT` | NOT NULL | 默认分支 |
|
||||
| `status` | `TEXT` | NOT NULL | `active / archived` |
|
||||
| `created_at` | `TEXT` | NOT NULL | 创建时间 |
|
||||
| `updated_at` | `TEXT` | NOT NULL | 更新时间 |
|
||||
|
||||
关系:
|
||||
|
||||
- `projects 1 -> N workspaces`
|
||||
|
||||
### 5.3 `workspaces`
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `id` | `TEXT` | PK | 工作区 ID |
|
||||
| `project_id` | `TEXT` | FK -> `projects.id` | 所属项目 |
|
||||
| `slug` | `TEXT` | NOT NULL, UNIQUE | 工作区标识 |
|
||||
| `name` | `TEXT` | NOT NULL | 展示名称 |
|
||||
| `root_path` | `TEXT` | NOT NULL, UNIQUE | 工作区路径 |
|
||||
| `base_branch` | `TEXT` | NOT NULL | 基线分支 |
|
||||
| `worktree_branch` | `TEXT` | NOT NULL, UNIQUE | 工作分支 |
|
||||
| `runtime_backend` | `TEXT` | NOT NULL | `local / container / remote` |
|
||||
| `status` | `TEXT` | NOT NULL | `active / paused / archived` |
|
||||
| `created_at` | `TEXT` | NOT NULL | 创建时间 |
|
||||
| `updated_at` | `TEXT` | NOT NULL | 更新时间 |
|
||||
|
||||
关系:
|
||||
|
||||
- `workspaces N -> 1 projects`
|
||||
- `workspaces 1 -> N topics`
|
||||
- `workspaces 1 -> N messages`
|
||||
- `workspaces 1 -> N requirements`
|
||||
- `workspaces 1 -> N discovery_rounds`
|
||||
- `workspaces 1 -> N workflow_runs`
|
||||
- `workspaces 1 -> N merge_requests`
|
||||
|
||||
### 5.4 `roles`
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `name` | `TEXT` | PK | 角色名,例如 `product` |
|
||||
| `title` | `TEXT` | NOT NULL | 展示名称 |
|
||||
| `category` | `TEXT` | NOT NULL | `product / delivery / review / discovery` |
|
||||
| `description` | `TEXT` | NOT NULL DEFAULT `''` | 角色说明 |
|
||||
| `is_enabled` | `INTEGER` | NOT NULL | 1 启用,0 禁用 |
|
||||
| `is_builtin` | `INTEGER` | NOT NULL | 1 内置,0 自定义 |
|
||||
| `sort_order` | `INTEGER` | NOT NULL DEFAULT `0` | 排序 |
|
||||
| `created_at` | `TEXT` | NOT NULL | 创建时间 |
|
||||
| `updated_at` | `TEXT` | NOT NULL | 更新时间 |
|
||||
|
||||
关系:
|
||||
|
||||
- `roles 1 -> N role_prompts`
|
||||
- `roles 1 -> N role_configs`
|
||||
- `roles 1 -> N role_skill_bindings`
|
||||
- `roles 1 -> N messages`
|
||||
- `roles 1 -> N message_deliveries`
|
||||
- `roles 1 -> N requirements`
|
||||
- `roles 1 -> N discovery_candidates`
|
||||
- `roles 1 -> N discovery_votes`
|
||||
- `roles 1 -> N workflow_runs`
|
||||
|
||||
### 5.5 `role_prompts`
|
||||
|
||||
当前生效的提示词表。
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `id` | `TEXT` | PK | 提示词记录 ID |
|
||||
| `role_name` | `TEXT` | FK -> `roles.name` | 所属角色 |
|
||||
| `workspace_id` | `TEXT` | FK -> `workspaces.id`, NULLABLE | 为空表示全局默认;非空表示 workspace override |
|
||||
| `prompt_kind` | `TEXT` | NOT NULL | `system / clarification / plan / review / freeze / execution / verification / discovery` |
|
||||
| `content_markdown` | `TEXT` | NOT NULL | 提示词正文 |
|
||||
| `version` | `INTEGER` | NOT NULL | 当前版本号 |
|
||||
| `updated_by` | `TEXT` | NOT NULL DEFAULT `''` | 修改人或修改来源 |
|
||||
| `created_at` | `TEXT` | NOT NULL | 创建时间 |
|
||||
| `updated_at` | `TEXT` | NOT NULL | 更新时间 |
|
||||
|
||||
唯一约束:
|
||||
|
||||
- 全局:每个 `(role_name, prompt_kind)` 只能有 1 条全局默认记录
|
||||
- 工作区:每个 `(role_name, workspace_id, prompt_kind)` 只能有 1 条 override 记录
|
||||
|
||||
关系:
|
||||
|
||||
- `role_prompts N -> 1 roles`
|
||||
- `role_prompts N -> 1 workspaces`(可空)
|
||||
|
||||
### 5.6 `role_configs`
|
||||
|
||||
当前生效的角色运行配置表。
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `id` | `TEXT` | PK | 配置记录 ID |
|
||||
| `role_name` | `TEXT` | FK -> `roles.name` | 所属角色 |
|
||||
| `workspace_id` | `TEXT` | FK -> `workspaces.id`, NULLABLE | 为空表示全局默认;非空表示 workspace override |
|
||||
| `model` | `TEXT` | NOT NULL DEFAULT `''` | 默认模型 |
|
||||
| `model_provider` | `TEXT` | NOT NULL DEFAULT `''` | 模型提供方 |
|
||||
| `provider_name` | `TEXT` | NOT NULL DEFAULT `''` | Provider 名称 |
|
||||
| `provider_base_url` | `TEXT` | NOT NULL DEFAULT `''` | Provider Base URL |
|
||||
| `provider_wire_api` | `TEXT` | NOT NULL DEFAULT `''` | Provider Wire API |
|
||||
| `reasoning_effort` | `TEXT` | NOT NULL DEFAULT `''` | 默认 reasoning 等级 |
|
||||
| `plan_model` | `TEXT` | NOT NULL DEFAULT `''` | 规划阶段专用模型 |
|
||||
| `plan_reasoning_effort` | `TEXT` | NOT NULL DEFAULT `''` | 规划阶段 reasoning |
|
||||
| `disable_response_storage` | `INTEGER` | NOT NULL DEFAULT `0` | 是否关闭响应持久化 |
|
||||
| `shell_env_inherit` | `TEXT` | NOT NULL DEFAULT `core` | 继承环境变量策略 |
|
||||
| `shell_env_overrides_json` | `TEXT` | NOT NULL DEFAULT `{}` | 环境变量覆盖项 |
|
||||
| `extra_config_json` | `TEXT` | NOT NULL DEFAULT `{}` | 其他扩展配置 |
|
||||
| `version` | `INTEGER` | NOT NULL | 当前版本号 |
|
||||
| `updated_by` | `TEXT` | NOT NULL DEFAULT `''` | 修改人或修改来源 |
|
||||
| `created_at` | `TEXT` | NOT NULL | 创建时间 |
|
||||
| `updated_at` | `TEXT` | NOT NULL | 更新时间 |
|
||||
|
||||
唯一约束:
|
||||
|
||||
- 全局:每个 `role_name` 只能有 1 条全局默认配置
|
||||
- 工作区:每个 `(role_name, workspace_id)` 只能有 1 条 override 配置
|
||||
|
||||
关系:
|
||||
|
||||
- `role_configs N -> 1 roles`
|
||||
- `role_configs N -> 1 workspaces`(可空)
|
||||
|
||||
### 5.7 `skills`
|
||||
|
||||
技能定义表。运行时真正使用数据库中的技能内容。
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `id` | `TEXT` | PK | 技能 ID |
|
||||
| `skill_key` | `TEXT` | NOT NULL, UNIQUE | 稳定标识 |
|
||||
| `name` | `TEXT` | NOT NULL | 展示名称 |
|
||||
| `description` | `TEXT` | NOT NULL DEFAULT `''` | 技能说明 |
|
||||
| `source_type` | `TEXT` | NOT NULL | `builtin / imported / custom` |
|
||||
| `content_markdown` | `TEXT` | NOT NULL DEFAULT `''` | 技能正文内容 |
|
||||
| `status` | `TEXT` | NOT NULL | `active / disabled / archived` |
|
||||
| `version` | `INTEGER` | NOT NULL | 当前版本号 |
|
||||
| `created_at` | `TEXT` | NOT NULL | 创建时间 |
|
||||
| `updated_at` | `TEXT` | NOT NULL | 更新时间 |
|
||||
|
||||
关系:
|
||||
|
||||
- `skills 1 -> N role_skill_bindings`
|
||||
|
||||
### 5.8 `role_skill_bindings`
|
||||
|
||||
角色与技能的绑定表。
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `id` | `TEXT` | PK | 绑定记录 ID |
|
||||
| `role_name` | `TEXT` | FK -> `roles.name` | 角色 |
|
||||
| `workspace_id` | `TEXT` | FK -> `workspaces.id`, NULLABLE | 为空表示全局默认;非空表示 workspace override |
|
||||
| `skill_id` | `TEXT` | FK -> `skills.id` | 技能 |
|
||||
| `is_enabled` | `INTEGER` | NOT NULL | 1 启用,0 禁用 |
|
||||
| `sort_order` | `INTEGER` | NOT NULL DEFAULT `0` | 排序 |
|
||||
| `config_json` | `TEXT` | NOT NULL DEFAULT `{}` | 绑定级配置 |
|
||||
| `version` | `INTEGER` | NOT NULL | 当前版本号 |
|
||||
| `updated_by` | `TEXT` | NOT NULL DEFAULT `''` | 修改人或修改来源 |
|
||||
| `created_at` | `TEXT` | NOT NULL | 创建时间 |
|
||||
| `updated_at` | `TEXT` | NOT NULL | 更新时间 |
|
||||
|
||||
唯一约束:
|
||||
|
||||
- 全局:每个 `(role_name, skill_id)` 只能有 1 条全局默认绑定
|
||||
- 工作区:每个 `(role_name, workspace_id, skill_id)` 只能有 1 条 override 绑定
|
||||
|
||||
关系:
|
||||
|
||||
- `role_skill_bindings N -> 1 roles`
|
||||
- `role_skill_bindings N -> 1 skills`
|
||||
- `role_skill_bindings N -> 1 workspaces`(可空)
|
||||
|
||||
### 5.10 `topics`
|
||||
|
||||
这是第二版的主实体表。
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `id` | `TEXT` | PK | topic ID |
|
||||
| `workspace_id` | `TEXT` | FK -> `workspaces.id` | 所属工作区 |
|
||||
| `slug` | `TEXT` | NOT NULL | 稳定标识 |
|
||||
| `title` | `TEXT` | NOT NULL | 标题 |
|
||||
| `space` | `TEXT` | NOT NULL | `discovery / clarify / pool / workflow` |
|
||||
| `status` | `TEXT` | NOT NULL | 当前状态 |
|
||||
| `source_topic_id` | `TEXT` | FK -> `topics.id`, NULLABLE | 来源 topic |
|
||||
| `owner_role_name` | `TEXT` | FK -> `roles.name`, NULLABLE | 当前主责角色 |
|
||||
| `summary` | `TEXT` | NOT NULL DEFAULT `''` | 摘要 |
|
||||
| `meta_json` | `TEXT` | NOT NULL DEFAULT `{}` | 扩展元数据 |
|
||||
| `created_at` | `TEXT` | NOT NULL | 创建时间 |
|
||||
| `updated_at` | `TEXT` | NOT NULL | 更新时间 |
|
||||
| `closed_at` | `TEXT` | NULLABLE | 关闭时间 |
|
||||
|
||||
唯一约束:
|
||||
|
||||
- 每个 workspace 下 `slug` 唯一
|
||||
|
||||
关系:
|
||||
|
||||
- `topics N -> 1 workspaces`
|
||||
- `topics N -> 1 topics`(`source_topic_id`)
|
||||
- `topics N -> 1 roles`(`owner_role_name`)
|
||||
- `topics 1 -> N topic_documents`
|
||||
- `topics 1 -> N messages`
|
||||
- `topics 1 -> N requirements`
|
||||
- `topics 1 -> N discovery_rounds`
|
||||
- `topics 1 -> N workflow_runs`
|
||||
- `topics 1 -> N merge_requests`
|
||||
|
||||
### 5.11 `topic_documents`
|
||||
|
||||
topic 持有的正式文档。
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `id` | `TEXT` | PK | 文档 ID |
|
||||
| `topic_id` | `TEXT` | FK -> `topics.id` | 所属 topic |
|
||||
| `kind` | `TEXT` | NOT NULL | `prd / decision_log / discovery_request / discovery_result` |
|
||||
| `content_markdown` | `TEXT` | NOT NULL | Markdown 正文 |
|
||||
| `version` | `INTEGER` | NOT NULL | 版本号 |
|
||||
| `updated_by_role_name` | `TEXT` | FK -> `roles.name`, NULLABLE | 最后更新角色 |
|
||||
| `created_at` | `TEXT` | NOT NULL | 创建时间 |
|
||||
| `updated_at` | `TEXT` | NOT NULL | 更新时间 |
|
||||
|
||||
唯一约束:
|
||||
|
||||
- 每个 topic 下每种 `kind` 只能有 1 条当前文档
|
||||
|
||||
说明:
|
||||
|
||||
- `PRD` 与 `Decision Log` 在 `v2` 中归 `product` 所有
|
||||
|
||||
### 5.12 `messages`
|
||||
|
||||
消息主表。
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `id` | `TEXT` | PK | 消息 ID |
|
||||
| `workspace_id` | `TEXT` | FK -> `workspaces.id` | 所属工作区 |
|
||||
| `topic_id` | `TEXT` | FK -> `topics.id` | 所属 topic |
|
||||
| `from_role_name` | `TEXT` | FK -> `roles.name` | 发送角色 |
|
||||
| `to_expr` | `TEXT` | NOT NULL | 原始收件表达式,例如 `backend`、`all` |
|
||||
| `type` | `TEXT` | NOT NULL | `chat / proposal / question / decision / summary` |
|
||||
| `stage` | `TEXT` | NOT NULL | `clarification / plan / review / freeze / execution / verification / discovery` |
|
||||
| `round` | `INTEGER` | NULLABLE | 回合号 |
|
||||
| `reply_to_message_id` | `TEXT` | FK -> `messages.id`, NULLABLE | 回复目标消息 |
|
||||
| `body_markdown` | `TEXT` | NOT NULL | 消息正文 |
|
||||
| `created_at` | `TEXT` | NOT NULL | 创建时间 |
|
||||
|
||||
关系:
|
||||
|
||||
- `messages N -> 1 workspaces`
|
||||
- `messages N -> 1 topics`
|
||||
- `messages N -> 1 roles`
|
||||
- `messages N -> 1 messages`(`reply_to_message_id`)
|
||||
- `messages 1 -> N message_deliveries`
|
||||
|
||||
### 5.13 `message_deliveries`
|
||||
|
||||
每个实际收件人的投递状态。
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `message_id` | `TEXT` | FK -> `messages.id` | 对应消息 |
|
||||
| `recipient_role_name` | `TEXT` | FK -> `roles.name` | 实际收件角色 |
|
||||
| `state` | `TEXT` | NOT NULL | `pending / received / read / archived` |
|
||||
| `delivered_at` | `TEXT` | NOT NULL | 投递时间 |
|
||||
| `read_at` | `TEXT` | NULLABLE | 已读时间 |
|
||||
| `archived_at` | `TEXT` | NULLABLE | 归档时间 |
|
||||
| `updated_at` | `TEXT` | NOT NULL | 更新时间 |
|
||||
|
||||
主键:
|
||||
|
||||
- `PRIMARY KEY (message_id, recipient_role_name)`
|
||||
|
||||
说明:
|
||||
|
||||
- `to: all` 会在这里展开成多条记录
|
||||
|
||||
|
||||
- 它只表达“线程绑定”
|
||||
- 不表达“这次执行的历史”
|
||||
|
||||
### 5.15 `requirements`
|
||||
|
||||
pool 阶段的结构化队列项。
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `id` | `TEXT` | PK | requirement ID |
|
||||
| `workspace_id` | `TEXT` | FK -> `workspaces.id` | 所属工作区 |
|
||||
| `topic_id` | `TEXT` | FK -> `topics.id` | 来源 topic |
|
||||
| `title` | `TEXT` | NOT NULL | 标题 |
|
||||
| `body_markdown` | `TEXT` | NOT NULL | 详细说明 |
|
||||
| `status` | `TEXT` | NOT NULL | `pending / dispatched / completed / archived` |
|
||||
| `priority` | `INTEGER` | NOT NULL | 优先级 |
|
||||
| `created_by_role_name` | `TEXT` | FK -> `roles.name` | 创建角色,通常是 `product` |
|
||||
| `created_at` | `TEXT` | NOT NULL | 创建时间 |
|
||||
| `updated_at` | `TEXT` | NOT NULL | 更新时间 |
|
||||
| `completed_at` | `TEXT` | NULLABLE | 完成时间 |
|
||||
|
||||
说明:
|
||||
|
||||
- `requirements` 以 `workspace + topic` 为来源
|
||||
- 不再把 `project_id` 当成 requirement 的主归属
|
||||
|
||||
### 5.16 `discovery_rounds`
|
||||
|
||||
discovery 轮次主表。
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `id` | `TEXT` | PK | round ID |
|
||||
| `workspace_id` | `TEXT` | FK -> `workspaces.id` | 所属工作区 |
|
||||
| `topic_id` | `TEXT` | FK -> `topics.id` | 关联 topic |
|
||||
| `phase` | `TEXT` | NOT NULL | `collecting / voting / completed / cancelled` |
|
||||
| `request_document_id` | `TEXT` | FK -> `topic_documents.id`, NULLABLE | discovery request 文档 |
|
||||
| `result_document_id` | `TEXT` | FK -> `topic_documents.id`, NULLABLE | discovery result 文档 |
|
||||
| `started_at` | `TEXT` | NOT NULL | 开始时间 |
|
||||
| `completed_at` | `TEXT` | NULLABLE | 完成时间 |
|
||||
| `updated_at` | `TEXT` | NOT NULL | 更新时间 |
|
||||
|
||||
关系:
|
||||
|
||||
- `discovery_rounds N -> 1 workspaces`
|
||||
- `discovery_rounds N -> 1 topics`
|
||||
- `discovery_rounds 1 -> N discovery_candidates`
|
||||
|
||||
### 5.17 `discovery_candidates`
|
||||
|
||||
discovery 候选项结构化表。
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `id` | `TEXT` | PK | candidate ID |
|
||||
| `round_id` | `TEXT` | FK -> `discovery_rounds.id` | 所属 round |
|
||||
| `proposer_role_name` | `TEXT` | FK -> `roles.name` | 提出角色 |
|
||||
| `status` | `TEXT` | NOT NULL | `draft / ready / accepted / rejected / archived` |
|
||||
| `title` | `TEXT` | NOT NULL | 候选标题 |
|
||||
| `problem` | `TEXT` | NOT NULL DEFAULT `''` | 问题描述 |
|
||||
| `evidence` | `TEXT` | NOT NULL DEFAULT `''` | 证据 |
|
||||
| `proposal` | `TEXT` | NOT NULL DEFAULT `''` | 提案内容 |
|
||||
| `expected_impact` | `TEXT` | NOT NULL DEFAULT `''` | 预期收益 |
|
||||
| `risk` | `TEXT` | NOT NULL DEFAULT `''` | 风险 |
|
||||
| `how_to_verify` | `TEXT` | NOT NULL DEFAULT `''` | 验证方式 |
|
||||
| `created_at` | `TEXT` | NOT NULL | 创建时间 |
|
||||
| `updated_at` | `TEXT` | NOT NULL | 更新时间 |
|
||||
|
||||
关系:
|
||||
|
||||
- `discovery_candidates N -> 1 discovery_rounds`
|
||||
- `discovery_candidates N -> 1 roles`
|
||||
- `discovery_candidates 1 -> N discovery_votes`
|
||||
|
||||
### 5.18 `discovery_votes`
|
||||
|
||||
discovery 候选项投票表。
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `id` | `TEXT` | PK | vote ID |
|
||||
| `round_id` | `TEXT` | FK -> `discovery_rounds.id` | 所属 round |
|
||||
| `candidate_id` | `TEXT` | FK -> `discovery_candidates.id` | 所投候选项 |
|
||||
| `voter_role_name` | `TEXT` | FK -> `roles.name` | 投票角色 |
|
||||
| `vote` | `TEXT` | NOT NULL | `agree / reject / unclear` |
|
||||
| `reason` | `TEXT` | NOT NULL DEFAULT `''` | 原因 |
|
||||
| `created_at` | `TEXT` | NOT NULL | 创建时间 |
|
||||
|
||||
唯一约束:
|
||||
|
||||
- 每个角色对每个候选项最多投 1 票
|
||||
|
||||
### 5.19 `workflow_runs`
|
||||
|
||||
执行阶段主表。
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `id` | `TEXT` | PK | run ID |
|
||||
| `workspace_id` | `TEXT` | FK -> `workspaces.id` | 所属工作区 |
|
||||
| `topic_id` | `TEXT` | FK -> `topics.id` | 所属 topic |
|
||||
| `role_name` | `TEXT` | FK -> `roles.name` | 执行角色 |
|
||||
| `stage` | `TEXT` | NOT NULL | `plan / review / execution / verification` |
|
||||
| `mode` | `TEXT` | NOT NULL DEFAULT `''` | 运行模式 |
|
||||
| `status` | `TEXT` | NOT NULL | `running / succeeded / failed / cancelled` |
|
||||
| `request_message_id` | `TEXT` | FK -> `messages.id`, NULLABLE | 触发消息 |
|
||||
| `config_snapshot_json` | `TEXT` | NOT NULL DEFAULT `{}` | 启动时解析出的 prompt/config/skills 快照 |
|
||||
| `command_json` | `TEXT` | NOT NULL DEFAULT `[]` | 执行命令快照 |
|
||||
| `reply_message_id` | `TEXT` | FK -> `messages.id`, NULLABLE | 执行完成后的回复消息 |
|
||||
| `exit_code` | `INTEGER` | NOT NULL DEFAULT `0` | 退出码 |
|
||||
| `started_at` | `TEXT` | NOT NULL | 开始时间 |
|
||||
| `completed_at` | `TEXT` | NULLABLE | 完成时间 |
|
||||
| `error_message` | `TEXT` | NOT NULL DEFAULT `''` | 错误信息 |
|
||||
|
||||
说明:
|
||||
|
||||
- 新的 run 启动时必须把解析后的角色配置快照写入 `config_snapshot_json`
|
||||
- 这样后续即使 prompt/config 被改动,历史 run 仍然可追溯
|
||||
|
||||
### 5.20 `workflow_run_logs`
|
||||
|
||||
执行日志流。
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `run_id` | `TEXT` | FK -> `workflow_runs.id` | 所属 run |
|
||||
| `seq` | `INTEGER` | NOT NULL | 行序号 |
|
||||
| `stream` | `TEXT` | NOT NULL | `stdout / stderr / system` |
|
||||
| `content` | `TEXT` | NOT NULL | 日志内容 |
|
||||
| `created_at` | `TEXT` | NOT NULL | 创建时间 |
|
||||
|
||||
主键:
|
||||
|
||||
- `PRIMARY KEY (run_id, seq)`
|
||||
|
||||
关系:
|
||||
|
||||
- `workflow_run_logs N -> 1 workflow_runs`
|
||||
|
||||
### 5.21 `merge_requests`
|
||||
|
||||
merge 请求记录。
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `id` | `TEXT` | PK | merge request ID |
|
||||
| `workspace_id` | `TEXT` | FK -> `workspaces.id` | 所属工作区 |
|
||||
| `topic_id` | `TEXT` | FK -> `topics.id` | 所属 topic |
|
||||
| `workflow_run_id` | `TEXT` | FK -> `workflow_runs.id`, NULLABLE | 来源执行记录 |
|
||||
| `requested_by_role_name` | `TEXT` | FK -> `roles.name`, NULLABLE | 发起角色 |
|
||||
| `target_branch` | `TEXT` | NOT NULL | 目标分支 |
|
||||
| `status` | `TEXT` | NOT NULL | `pending / merged / failed / cancelled` |
|
||||
| `summary` | `TEXT` | NOT NULL DEFAULT `''` | 摘要 |
|
||||
| `files_changed` | `INTEGER` | NOT NULL DEFAULT `0` | 改动文件数 |
|
||||
| `insertions` | `INTEGER` | NOT NULL DEFAULT `0` | 新增行数 |
|
||||
| `deletions` | `INTEGER` | NOT NULL DEFAULT `0` | 删除行数 |
|
||||
| `changed_files_json` | `TEXT` | NOT NULL DEFAULT `[]` | 改动文件列表 |
|
||||
| `created_at` | `TEXT` | NOT NULL | 创建时间 |
|
||||
| `merged_at` | `TEXT` | NULLABLE | 合并时间 |
|
||||
| `error_message` | `TEXT` | NOT NULL DEFAULT `''` | 失败原因 |
|
||||
|
||||
关系:
|
||||
|
||||
- `merge_requests N -> 1 workspaces`
|
||||
- `merge_requests N -> 1 topics`
|
||||
- `merge_requests N -> 1 workflow_runs`
|
||||
- `merge_requests N -> 1 roles`
|
||||
|
||||
## 6. 表关系图
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
PROJECTS ||--o{ WORKSPACES : has
|
||||
WORKSPACES ||--o{ TOPICS : owns
|
||||
WORKSPACES ||--o{ MESSAGES : owns
|
||||
WORKSPACES ||--o{ REQUIREMENTS : owns
|
||||
WORKSPACES ||--o{ DISCOVERY_ROUNDS : owns
|
||||
WORKSPACES ||--o{ WORKFLOW_RUNS : owns
|
||||
WORKSPACES ||--o{ MERGE_REQUESTS : owns
|
||||
|
||||
ROLES ||--o{ ROLE_PROMPTS : has
|
||||
ROLES ||--o{ ROLE_CONFIGS : has
|
||||
ROLES ||--o{ ROLE_SKILL_BINDINGS : binds
|
||||
SKILLS ||--o{ ROLE_SKILL_BINDINGS : used_by
|
||||
|
||||
TOPICS ||--o{ TOPIC_DOCUMENTS : has
|
||||
TOPICS ||--o{ MESSAGES : contains
|
||||
TOPICS ||--o{ REQUIREMENTS : produces
|
||||
TOPICS ||--o{ DISCOVERY_ROUNDS : drives
|
||||
TOPICS ||--o{ WORKFLOW_RUNS : executes
|
||||
TOPICS ||--o{ MERGE_REQUESTS : results_in
|
||||
|
||||
MESSAGES ||--o{ MESSAGE_DELIVERIES : fans_out
|
||||
MESSAGES ||--o{ MESSAGES : replies_to
|
||||
|
||||
DISCOVERY_ROUNDS ||--o{ DISCOVERY_CANDIDATES : includes
|
||||
DISCOVERY_CANDIDATES ||--o{ DISCOVERY_VOTES : receives
|
||||
|
||||
WORKFLOW_RUNS ||--o{ WORKFLOW_RUN_LOGS : emits
|
||||
WORKFLOW_RUNS ||--o| MERGE_REQUESTS : may_create
|
||||
```
|
||||
|
||||
## 7. 关系说明
|
||||
|
||||
### 7.1 配置关系
|
||||
|
||||
| 主表 | 从表 | 关系 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `roles` | `role_prompts` | 1:N | 一个角色可有多种 prompt kind,也可有 workspace override |
|
||||
| `roles` | `role_configs` | 1:N | 一个角色可有全局配置和多个 workspace override |
|
||||
| `roles` | `role_skill_bindings` | 1:N | 一个角色可绑定多个技能 |
|
||||
| `skills` | `role_skill_bindings` | 1:N | 一个技能可被多个角色使用 |
|
||||
| `workspaces` | `role_prompts / role_configs / role_skill_bindings` | 1:N | workspace 级覆盖配置 |
|
||||
|
||||
### 7.2 业务关系
|
||||
|
||||
| 主表 | 从表 | 关系 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `projects` | `workspaces` | 1:N | 一个项目下有多个工作区 |
|
||||
| `workspaces` | `topics` | 1:N | 一个工作区下有多个 topic |
|
||||
| `topics` | `topic_documents` | 1:N | 一个 topic 下有多种文档 |
|
||||
| `topics` | `messages` | 1:N | 一个 topic 下有多条消息 |
|
||||
| `messages` | `message_deliveries` | 1:N | 一条消息可投递给多个角色 |
|
||||
| `topics` | `requirements` | 1:N | 一个 topic 可产生多个 requirement |
|
||||
| `topics` | `discovery_rounds` | 1:N | 一个 topic 可有多轮 discovery |
|
||||
| `discovery_rounds` | `discovery_candidates` | 1:N | 一轮 discovery 可有多个候选项 |
|
||||
| `discovery_candidates` | `discovery_votes` | 1:N | 一个候选项可收到多个角色投票 |
|
||||
| `topics` | `workflow_runs` | 1:N | 一个 topic 可有多次执行 |
|
||||
| `workflow_runs` | `workflow_run_logs` | 1:N | 一次执行有多条日志 |
|
||||
| `topics` | `merge_requests` | 1:N | 一个 topic 可产生多个 merge 请求 |
|
||||
|
||||
### 7.3 特殊关系
|
||||
|
||||
| 字段 | 关系 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `topics.source_topic_id` | 自关联 | topic 可从另一个 topic 派生 |
|
||||
| `messages.reply_to_message_id` | 自关联 | 消息可回复另一条消息 |
|
||||
| `discovery_rounds.request_document_id` | 指向 `topic_documents` | discovery 输入文档 |
|
||||
| `discovery_rounds.result_document_id` | 指向 `topic_documents` | discovery 输出文档 |
|
||||
| `workflow_runs.config_snapshot_json` | 快照,不是 FK | 保存运行时解析后的配置结果 |
|
||||
|
||||
## 8. 读取优先级
|
||||
|
||||
以下三张配置表都采用相同规则:
|
||||
|
||||
- `role_prompts`
|
||||
- `role_configs`
|
||||
- `role_skill_bindings`
|
||||
|
||||
读取顺序固定为:
|
||||
|
||||
1. 先查当前 `workspace_id` 的覆盖记录
|
||||
2. 如果没有,再查全局默认记录
|
||||
|
||||
这个规则是 `v2` 的硬约束,服务端、测试和前端都按这套理解实现。
|
||||
|
||||
## 9. 写入规则
|
||||
|
||||
### 9.1 配置写入
|
||||
|
||||
当用户在前端修改:
|
||||
|
||||
- 角色
|
||||
- 提示词
|
||||
- 技能
|
||||
- 角色配置
|
||||
- 技能绑定
|
||||
|
||||
服务端必须同时做两件事:
|
||||
|
||||
1. 更新当前生效表
|
||||
|
||||
### 9.2 新执行启动
|
||||
|
||||
当新的 `workflow_runs` 启动时:
|
||||
|
||||
1. 解析角色最终生效配置
|
||||
- prompt
|
||||
- role config
|
||||
- skill binding
|
||||
- skill 内容
|
||||
2. 将解析结果写入 `workflow_runs.config_snapshot_json`
|
||||
3. 再启动实际执行
|
||||
|
||||
这样可以同时满足:
|
||||
|
||||
- 配置立即生效
|
||||
- 历史执行可追溯
|
||||
|
||||
## 10. V2 明确不保留的旧表
|
||||
|
||||
| 旧表 | V2 处理 |
|
||||
| --- | --- |
|
||||
| `topic_records` | 删除,合并进 `topics` |
|
||||
| `clarifier_state` | 删除,状态回归 `topics` |
|
||||
| `clarifier_artifacts` | 删除,合并进 `topic_documents` |
|
||||
| `message_mailboxes` | 改为 `message_deliveries` |
|
||||
| `dispatches` | 改为 `workflow_runs` |
|
||||
| `dispatch_live_lines` | 改为 `workflow_run_logs` |
|
||||
| `discovery_round_proposals` | 删除,改为 `discovery_candidates` |
|
||||
| `discovery_round_votes` JSON blob | 删除,改为结构化 `discovery_votes` |
|
||||
|
||||
## 11. 对开发的直接约束
|
||||
|
||||
这份文档对 `v2` 开发有三条直接约束:
|
||||
|
||||
1. 不允许再出现“同一业务对象散落多个旧表”的设计。
|
||||
2. 不允许再把在线可编辑配置只放文件、不进数据库。
|
||||
3. 不允许再把 discovery 和 workflow 的核心结构塞回 JSON blob。
|
||||
|
||||
这份文档就是 `inbox v2` 的数据库基线,后续如果要改,应该直接更新这份文档,而不是各模块各自理解一版。
|
||||
|
||||
## 当前工作流图扩展
|
||||
|
||||
当前运行时已经在 `chains` / `tasks` / `workflow_runs` 上扩展了 leader-managed graph 字段,作为后续 DAG planning 的基础。
|
||||
|
||||
### chains
|
||||
|
||||
除基础标识与运行态字段外,`chains` 当前还包含:
|
||||
|
||||
- `purpose`:这条 chain 的目标与职责摘要
|
||||
|
||||
### tasks
|
||||
|
||||
除基础标题、正文、状态、依赖字段外,`tasks` 当前还包含:
|
||||
|
||||
- `task_kind`
|
||||
- `execution`
|
||||
- `gate`
|
||||
- `verification`
|
||||
- `milestone`
|
||||
- `gate_policy`
|
||||
- `none`
|
||||
- `hard_stop`
|
||||
- `ask_user`
|
||||
- `leader_replan`
|
||||
- `deliverables_json`
|
||||
- `verification_mode`
|
||||
- `none`
|
||||
- `auto`
|
||||
- `human`
|
||||
- `batch_key`
|
||||
- `replan_policy`
|
||||
- `patch`
|
||||
- `clarify`
|
||||
- `stop`
|
||||
|
||||
说明:
|
||||
|
||||
- `task_kind = milestone` 是当前 milestone 的落地方式,不单独建表。
|
||||
- `gate` task 用于前置检查;存在 gate 时,其它 task 默认先不放行。
|
||||
|
||||
### workflow_runs
|
||||
|
||||
`leader` 的结构化 planning 结果当前会持久化到:
|
||||
|
||||
- `workflow_runs.command_json`
|
||||
|
||||
其中包含:
|
||||
|
||||
- `plan_version`
|
||||
- `plan_mode`
|
||||
- `replan_reason`
|
||||
- `supersedes`
|
||||
- `execution_mode`
|
||||
- `leader_reply`
|
||||
- `chains`
|
||||
- `tasks`
|
||||
- `start_nodes`
|
||||
|
||||
说明:
|
||||
|
||||
- 空图首次规划使用 `plan_mode = initial`
|
||||
- 主题已有 graph 时,leader 必须使用 `plan_mode = patch`
|
||||
- 当前系统不允许 patch 模式扩图;patch 只能复用现有 graph
|
||||
@@ -0,0 +1,380 @@
|
||||
# Inbox V2 P1
|
||||
|
||||
本文档定义 `inbox v2` 的 `P1` 范围。
|
||||
`P1` 只包含“独立模块”。
|
||||
|
||||
这里的独立模块,不是指“所有包彼此完全隔离”,而是指:
|
||||
|
||||
- 不依赖 `store`、`runtime`、`agent runner`、`HTTP route`、`app service`
|
||||
- 可以单独实现、单独测试
|
||||
- 可以作为后续 `HTTP`、`app service`、`store`、`client` 的公共基础
|
||||
- 允许按分层方向依赖更底层的 `P1` 模块
|
||||
|
||||
换句话说:
|
||||
|
||||
- `P1` 要先固定“底层规则和模型”
|
||||
- `P1` 不要先混入“流程装配和基础设施”
|
||||
- `P1` 内部允许存在清晰的自底向上依赖
|
||||
|
||||
`P1` 的目标不是先把服务跑起来,而是先把最底层、最稳定、最可复用的规则和模型固定下来。
|
||||
|
||||
数据库设计草案见 [docs/inbox-v2-database.md](./inbox-v2-database.md)。
|
||||
|
||||
## 背景
|
||||
|
||||
`inbox v2` 的主线已经明确:
|
||||
|
||||
- `HTTP` 是唯一业务入口
|
||||
- `server` 是唯一正式启动入口
|
||||
- `CLI` 只是给 AI 使用的 `HTTP` 封装
|
||||
- `clarifier` 角色移除
|
||||
- `product` 接管需求整理,并继续输出:
|
||||
- `PRD`
|
||||
- `Decision Log`
|
||||
- `discovery` 保留
|
||||
- 交互路径暂时保持:
|
||||
- discovery
|
||||
- 需求整理
|
||||
- pool
|
||||
- workflow
|
||||
|
||||
在这条主线下,最先该实现的不是 server,也不是 client,而是底层独立模块。
|
||||
|
||||
## P1 设计原则
|
||||
|
||||
1. `P1` 模块必须独立于基础设施层,但允许依赖更底层的 `P1` 模块。
|
||||
2. `P1` 模块优先承载“稳定规则”,而不是“流程编排”。
|
||||
3. `P1` 模块一旦定型,后续 `P2/P3` 都应复用它们,而不是复制一份。
|
||||
4. `P1` 模块必须有单元测试。
|
||||
5. `P1` 不实现 HTTP route、不实现 runtime 装配、不实现数据库。
|
||||
|
||||
## P1 分层
|
||||
|
||||
为了让后续实现可落地,`P1` 采用下面这套分层:
|
||||
|
||||
| 层级 | 类型 | 可以依赖 |
|
||||
| --- | --- | --- |
|
||||
| `L0` | 基础工具 | Go 标准库 |
|
||||
| `L1` | 文档规范 | `L0` + Go 标准库 |
|
||||
| `L2` | 核心领域 | `L0/L1` + Go 标准库 |
|
||||
| `L3` | 领域组合规则 | `L0/L1/L2` + Go 标准库 |
|
||||
|
||||
约束只有一条:
|
||||
|
||||
- 依赖只能向下,不能横向乱连,更不能回依赖 `P2/P3`
|
||||
|
||||
## P1 模块清单
|
||||
|
||||
下面这些是 `inbox v2` 第一阶段应先落下的独立模块。
|
||||
|
||||
| 模块 | 建议路径 | 作用 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| 时间模块 | `internal/base/timeutil` | UTC 时间、标准时间格式、可注入 clock | 给记录、文档更新时间、事件时间统一格式 |
|
||||
| 标识符模块 | `internal/base/idgen` | topic / message / requirement / merge request 等 ID 生成规则 | 先固定命名和生成策略 |
|
||||
| slug 模块 | `internal/base/slug` | topic、workspace、project 的 slug 规范化 | 这是所有上层都会复用的基础规则 |
|
||||
| HTTP 通用模块 | `internal/base/httpx` | 状态错误、JSON 编解码、通用响应封装 | 只做 transport 基础工具,不做具体业务 |
|
||||
| 文档模板模块 | `internal/domain/docspec` | `PRD`、`Decision Log`、Discovery request/result 的模板与渲染规则 | `product` 将直接依赖它 |
|
||||
| 消息模块 | `internal/domain/message` | message envelope、front matter 解析、渲染、收件人规则 | 统一所有消息文档格式 |
|
||||
| Topic 模块 | `internal/domain/topic` | topic 的 space/status 生命周期规则 | 明确 clarify/pool/workflow/discovery 的推进规则 |
|
||||
| Role 模块 | `internal/domain/role` | 角色分类、角色定义、角色能力边界 | 包括 `product`、`backend`、`frontend`、`reviewer`、discovery 系列 |
|
||||
| Requirement 模块 | `internal/domain/requirement` | requirement 的结构、状态、优先级与验证规则 | pool 的结构化实体先独立出来 |
|
||||
| Discovery 模块 | `internal/domain/discovery` | discovery 提案、投票、共识计算、结果文档规则 | 保留 discovery 的核心领域逻辑 |
|
||||
| Workflow 模块 | `internal/domain/workflow` | workflow 阶段枚举、阶段合法流转、角色协作规则 | 只管规则,不管看板聚合 |
|
||||
| Merge 模块 | `internal/domain/merge` | merge request 状态、元数据结构、状态流转规则 | 只管领域规则,不管 git 命令 |
|
||||
|
||||
## P1 依赖关系
|
||||
|
||||
下面是建议的依赖方向。
|
||||
|
||||
| 模块 | 层级 | 可依赖模块 |
|
||||
| --- | --- | --- |
|
||||
| `timeutil` | `L0` | 无 |
|
||||
| `slug` | `L0` | 无 |
|
||||
| `idgen` | `L0` | `timeutil`, `slug` |
|
||||
| `httpx` | `L0` | 无 |
|
||||
| `docspec` | `L1` | `timeutil` |
|
||||
| `role` | `L2` | 无 |
|
||||
| `topic` | `L2` | `slug` |
|
||||
| `workflow` | `L2` | `role`, `topic` |
|
||||
| `requirement` | `L2` | `slug` |
|
||||
| `merge` | `L2` | `timeutil`, `idgen`, `slug` |
|
||||
| `message` | `L3` | `role`, `topic`, `workflow`, `slug`, `timeutil` |
|
||||
| `discovery` | `L3` | `role`, `docspec`, `idgen`, `timeutil`, `slug` |
|
||||
|
||||
这张表的意义是:
|
||||
|
||||
- `P1` 仍然是独立模块集合
|
||||
- 但不是人为禁止复用
|
||||
- 后续实现时可以从 `L0` 往上逐层推进
|
||||
|
||||
## P1 模块详细职责
|
||||
|
||||
### 1. `timeutil`
|
||||
|
||||
负责:
|
||||
|
||||
- `NowUTC()`
|
||||
- RFC3339 / RFC3339Nano 格式化
|
||||
- 可注入 clock
|
||||
|
||||
不负责:
|
||||
|
||||
- 调度
|
||||
- 轮询
|
||||
- timeout 策略
|
||||
|
||||
### 2. `idgen`
|
||||
|
||||
负责:
|
||||
|
||||
- message ID 规则
|
||||
- requirement ID 规则
|
||||
- merge request ID 规则
|
||||
- discovery round ID / candidate ID 规则
|
||||
|
||||
不负责:
|
||||
|
||||
- 数据库存储
|
||||
- 去重查询
|
||||
|
||||
### 3. `slug`
|
||||
|
||||
负责:
|
||||
|
||||
- topic slugify
|
||||
- workspace slugify
|
||||
- project slugify
|
||||
- 安全截断规则
|
||||
|
||||
不负责:
|
||||
|
||||
- 校验是否重名
|
||||
- 路径解析
|
||||
|
||||
### 4. `httpx`
|
||||
|
||||
负责:
|
||||
|
||||
- `WriteJSON`
|
||||
- `WriteError`
|
||||
- `ErrorWithStatus`
|
||||
- 通用 JSON decode 辅助
|
||||
- CORS 等通用 transport helper
|
||||
|
||||
不负责:
|
||||
|
||||
- route 注册
|
||||
- 业务 request/response
|
||||
|
||||
### 5. `docspec`
|
||||
|
||||
这是 `P1` 里非常关键的模块。
|
||||
|
||||
负责:
|
||||
|
||||
- `PRD` 模板
|
||||
- `Decision Log` 模板
|
||||
- Discovery request 文档格式
|
||||
- Discovery result 文档格式
|
||||
- 文档 front matter 规范
|
||||
- 文档固定章节顺序
|
||||
|
||||
不负责:
|
||||
|
||||
- 文档存储
|
||||
- 文档版本管理
|
||||
- 文档归属权限
|
||||
|
||||
这里要明确:
|
||||
|
||||
- 第二版中 `product` 会直接使用 `PRD` 和 `Decision Log`
|
||||
- 模板沿用当前澄清模板,但所有权从 `clarifier` 转到 `product`
|
||||
|
||||
### 6. `message`
|
||||
|
||||
负责:
|
||||
|
||||
- message envelope 结构
|
||||
- YAML front matter 解析
|
||||
- markdown 渲染
|
||||
- `from / to / type / topic / stage / reply_to / round` 规则
|
||||
- 收件人解析
|
||||
- 基础合法性校验
|
||||
- 面向消息文档的稳定结构定义
|
||||
|
||||
不负责:
|
||||
|
||||
- 消息存储
|
||||
- mailbox 查询
|
||||
- HTTP handler
|
||||
|
||||
### 7. `topic`
|
||||
|
||||
负责:
|
||||
|
||||
- topic `space`
|
||||
- `clarify`
|
||||
- `pool`
|
||||
- `workflow`
|
||||
- `discovery`
|
||||
- topic `status`
|
||||
- space/status 的默认值
|
||||
- 合法推进规则
|
||||
- “能升不能降”之类的基础约束
|
||||
|
||||
不负责:
|
||||
|
||||
- topic record 存储
|
||||
- topic 列表聚合
|
||||
|
||||
注意:
|
||||
|
||||
虽然 v2 去掉 `clarifier` 角色,但 `clarify` 这个对话整理阶段可以在兼容期继续存在;只是它背后的角色从 `clarifier` 变成 `product`。
|
||||
|
||||
### 8. `role`
|
||||
|
||||
负责:
|
||||
|
||||
- 角色枚举和分类
|
||||
- 角色合法性校验
|
||||
- 角色阶段边界
|
||||
- 哪些角色属于 discovery
|
||||
- 哪些角色属于 workflow
|
||||
- `product` 的正式职责定义
|
||||
|
||||
不负责:
|
||||
|
||||
- role 存储
|
||||
- role 技能绑定
|
||||
|
||||
### 9. `requirement`
|
||||
|
||||
负责:
|
||||
|
||||
- requirement 结构
|
||||
- requirement 状态
|
||||
- `pending`
|
||||
- `dispatched`
|
||||
- `completed`
|
||||
- `archived`
|
||||
- 优先级范围和校验
|
||||
- requirement 文本字段校验
|
||||
|
||||
不负责:
|
||||
|
||||
- requirement 查询
|
||||
- requirement dispatch 执行
|
||||
|
||||
### 10. `discovery`
|
||||
|
||||
负责:
|
||||
|
||||
- discovery candidate 结构
|
||||
- vote 结构
|
||||
- 共识判断
|
||||
- result markdown 生成
|
||||
- discovery request 文本格式规则
|
||||
- discovery 阶段的固定角色集合规则
|
||||
|
||||
不负责:
|
||||
|
||||
- 并发执行
|
||||
- codex 调用
|
||||
- round 持久化
|
||||
|
||||
### 11. `workflow`
|
||||
|
||||
负责:
|
||||
|
||||
- workflow 阶段枚举
|
||||
- `plan`
|
||||
- `review`
|
||||
- `execution`
|
||||
- `verification`
|
||||
- workflow 阶段流转规则
|
||||
- workflow 角色协作边界
|
||||
- workflow 消息的基础规则
|
||||
|
||||
不负责:
|
||||
|
||||
- workflow board 聚合
|
||||
- dispatch 查询
|
||||
|
||||
### 12. `merge`
|
||||
|
||||
负责:
|
||||
|
||||
- merge request 结构
|
||||
- merge request 状态流转
|
||||
- merge metadata 规则
|
||||
|
||||
不负责:
|
||||
|
||||
- git diff
|
||||
- merge 命令执行
|
||||
|
||||
## P1 明确不做的东西
|
||||
|
||||
下面这些不属于 `P1`:
|
||||
|
||||
- `server`
|
||||
- `client`
|
||||
- `http route`
|
||||
- `app service`
|
||||
- `store`
|
||||
- `runtime`
|
||||
- `agent runner`
|
||||
- `workflow board`
|
||||
- `pool dispatch`
|
||||
- `merge` 的 git 执行
|
||||
|
||||
这些模块都依赖更高层或外部设施,不属于独立底层模块。
|
||||
|
||||
## P1 实现顺序
|
||||
|
||||
建议顺序如下:
|
||||
|
||||
1. `timeutil`
|
||||
2. `slug`
|
||||
3. `idgen`
|
||||
4. `httpx`
|
||||
5. `docspec`
|
||||
6. `role`
|
||||
7. `topic`
|
||||
8. `workflow`
|
||||
9. `requirement`
|
||||
10. `merge`
|
||||
11. `message`
|
||||
12. `discovery`
|
||||
|
||||
原因很简单:
|
||||
|
||||
- 先做通用基础能力
|
||||
- 再做文档规范
|
||||
- 再做核心领域规则
|
||||
- 最后做组合型领域模块
|
||||
- 最后才进入 `P2` 的 `server/app/store`
|
||||
|
||||
## P1 输出结果
|
||||
|
||||
`P1` 完成后,应该得到这些结果:
|
||||
|
||||
1. 一组独立于基础设施的底层模块。
|
||||
2. 一组稳定的领域结构、模板和状态流转规则。
|
||||
3. 第二版可以明确复用的文档标准:
|
||||
- `PRD`
|
||||
- `Decision Log`
|
||||
- Discovery request
|
||||
- Discovery result
|
||||
4. 一套从 `L0 -> L3` 的清晰依赖方向。
|
||||
5. 后续 `P2` 实现 `HTTP server` 和 `app services` 时,不再需要重新发明这些规则。
|
||||
|
||||
## P1 完成标准
|
||||
|
||||
满足下面条件,`P1` 才算完成:
|
||||
|
||||
1. 上述每个模块都有明确目录。
|
||||
2. 每个模块都有单元测试。
|
||||
3. 每个模块都只依赖下层 `P1` 模块,不依赖任何 `P2/P3` 模块。
|
||||
4. 文档模板和领域规则已经固定。
|
||||
5. `product` 接管需求文档这一决策已经在底层模型中可以表达。
|
||||
@@ -0,0 +1,648 @@
|
||||
# Lane Worktree 物化与代码流转改造计划
|
||||
|
||||
本文档定义 `inbox v2` 中 `lane -> worktree -> runtime` 的代码流转改造方案。
|
||||
|
||||
目标很明确:
|
||||
|
||||
- 保留 `lane` 级隔离执行能力
|
||||
- 让下游 `lane` 能消费上游 `lane` 的真实代码产物
|
||||
- 避免 worker summary 充当“伪代码同步”
|
||||
- 逐步把当前执行模型修正为“依赖图 = 代码图”
|
||||
|
||||
本文档按阶段拆分,便于逐步实现和回归。
|
||||
|
||||
## 背景
|
||||
|
||||
当前系统已经把术语统一到 `lane`,但运行时还存在一个关键缺口:
|
||||
|
||||
- `leader` 规划出 task DAG
|
||||
- 系统按 task 依赖自动派生 execution lanes
|
||||
- 每个 `lane` 都有独立 `worktree` 和 `podman` 容器
|
||||
- 但跨 `lane` 的依赖目前只传递 worker summary,不传递代码
|
||||
|
||||
这会导致一个结果:
|
||||
|
||||
- 调度层认为 `Task B` 依赖 `Task A`
|
||||
- 运行层却没有把 `Task A` 的代码产物同步给 `Task B`
|
||||
- `Task B` 只能在自己的空 worktree 里“重建”上游结果
|
||||
|
||||
这不是真正的依赖执行,而是“读摘要后重写”。
|
||||
|
||||
## 真实问题示例:`todo-lane-smoke-2`
|
||||
|
||||
`todo-lane-smoke-2` 的 task 图如下:
|
||||
|
||||
1. `Scaffold full-stack project structure`
|
||||
2. `Implement Todo API with SQLite`
|
||||
3. `Implement React Todo UI`
|
||||
4. `Integrate stack and verify runnable demo`
|
||||
5. `Todo demo ready for review`
|
||||
|
||||
其依赖关系如下:
|
||||
|
||||
- `Scaffold full-stack project structure`:根任务
|
||||
- `Implement Todo API with SQLite`:依赖 `Scaffold`
|
||||
- `Implement React Todo UI`:依赖 `Scaffold`
|
||||
- `Integrate stack and verify runnable demo`:依赖 `Backend API` + `Frontend App`
|
||||
- `Todo demo ready for review`:依赖 `Integrate`
|
||||
|
||||
当前系统会把它派生成 4 条 execution lanes:
|
||||
|
||||
- `Foundation Setup`
|
||||
- `Backend API`
|
||||
- `Frontend App`
|
||||
- `Integration And Verification`
|
||||
|
||||
问题在于:
|
||||
|
||||
- `Backend API` 和 `Frontend App` 在各自 worktree 中写代码
|
||||
- `Integration And Verification` 也在自己的 worktree 中执行
|
||||
- 但它拿不到前两个 lane 的真实代码,只能拿到消息摘要
|
||||
|
||||
这意味着 `Integration` 不是在“上游代码之上做集成”,而是在“读了两段总结之后重新拼代码”。
|
||||
|
||||
## 总目标
|
||||
|
||||
实施完成后,系统应满足以下条件:
|
||||
|
||||
- 每个代码型 `lane` 都有可复用的 git 产物,而不是只有未提交改动
|
||||
- 下游 `lane` 启动前可以显式物化上游 `lane` 的代码输入
|
||||
- `lane` 之间的依赖关系能在 git 历史中体现出来
|
||||
- merge 冲突会显式阻塞执行,而不是被摘要绕过
|
||||
- `milestone` / `gate` 不再滥用独立 worktree
|
||||
- `lane` 是“代码演进线”,不是“任意 task 容器”
|
||||
|
||||
## 术语
|
||||
|
||||
本文统一使用以下术语:
|
||||
|
||||
- `lane`:执行泳道,代表一条相对连续的代码演进线
|
||||
- `worktree`:该 `lane` 对应的 git 工作目录
|
||||
- `runtime`:该 `lane` 对应的容器与 worker 进程
|
||||
- `snapshot`:某个 `lane` 在成功完成代码任务后的已提交 git 状态
|
||||
- `materialization`:将上游 `lane` 的代码输入同步到当前 `lane`
|
||||
|
||||
## 设计原则
|
||||
|
||||
### 1. 代码依赖必须用代码流转表达
|
||||
|
||||
只要下游 task 需要基于上游代码继续开发、联调、验证,就必须物化上游代码,而不是只传摘要。
|
||||
|
||||
### 2. lane 隔离要保留,但不能成为代码孤岛
|
||||
|
||||
`lane` 的价值是隔离并行开发,不是让每个 worker 在自己的平行宇宙里重写同一份实现。
|
||||
|
||||
### 3. 失败要显式
|
||||
|
||||
如果下游 lane 在物化上游代码时发生 merge 冲突,应显式标记 `blocked`,并触发 replan 或人工介入。
|
||||
|
||||
### 4. 优先 clean replacement,不做兼容分叉
|
||||
|
||||
不增加“新老同步方式同时存在”的运行时兼容逻辑。
|
||||
|
||||
应使用显式 schema / 数据迁移把新模型落下。
|
||||
|
||||
### 5. runtime 职责保持窄边界
|
||||
|
||||
- `workspaceruntime` 负责 ensure worktree / container
|
||||
- `taskexec` 负责调度与状态推进
|
||||
- git 产物提交与代码物化应放在单独模块中
|
||||
|
||||
不要把代码同步逻辑散落到 handler、runtime、leader prompt 中。
|
||||
|
||||
## 非目标
|
||||
|
||||
本计划不包含以下内容:
|
||||
|
||||
- 多机调度
|
||||
- 远程仓库 push / pull
|
||||
- GitHub / GitLab PR 集成
|
||||
- 二进制产物仓库
|
||||
- 通用 artifact storage
|
||||
- 对历史旧 topic 的运行时兼容兜底
|
||||
|
||||
## 理想工作流
|
||||
|
||||
拿 `todo-lane-smoke-2` 举例,理想形态如下。
|
||||
|
||||
### Lane 拆分
|
||||
|
||||
保留 4 条 execution lanes,但语义要变:
|
||||
|
||||
1. `Foundation Setup lane`
|
||||
从 `main` 起步,产出基础脚手架代码快照。
|
||||
|
||||
2. `Backend API lane`
|
||||
从 `Foundation Setup` 的代码快照起步,负责后端与 SQLite。
|
||||
|
||||
3. `Frontend App lane`
|
||||
从 `Foundation Setup` 的代码快照起步,负责 React 前端。
|
||||
|
||||
4. `Integration And Verification lane`
|
||||
在开始执行前,先物化:
|
||||
- `Foundation Setup`
|
||||
- `Backend API`
|
||||
- `Frontend App`
|
||||
|
||||
然后再做联调、启动脚本、验证、补丁修复。
|
||||
|
||||
5. `Todo demo ready for review`
|
||||
这是 `milestone`,不需要独立 worktree。
|
||||
|
||||
### Git 视角下的理想状态
|
||||
|
||||
- `Foundation Setup lane` 成功后,lane 分支上至少有一笔提交
|
||||
- `Backend API lane` 成功后,lane 分支上至少有一笔提交
|
||||
- `Frontend App lane` 成功后,lane 分支上至少有一笔提交
|
||||
- `Integration` 开始前,自己的 branch 已显式 merge 上游分支
|
||||
|
||||
换句话说,`Integration` 看到的应该是:
|
||||
|
||||
- `foundation commit`
|
||||
- `backend commit`
|
||||
- `frontend commit`
|
||||
|
||||
而不是:
|
||||
|
||||
- “Backend worker 说自己完成了”
|
||||
- “Frontend worker 说自己完成了”
|
||||
|
||||
## 当前缺口
|
||||
|
||||
### 缺口 1:代码没有被自动提交
|
||||
|
||||
当前 worker 执行成功后,代码通常还停留在未提交状态。
|
||||
|
||||
这会导致:
|
||||
|
||||
- 上游 `lane` 没有稳定的可消费产物
|
||||
- 下游即使要 merge,也没有明确的输入 commit
|
||||
|
||||
### 缺口 2:下游 lane 没有物化步骤
|
||||
|
||||
当前 `taskexec` 在给 worker 分配任务前,不会把依赖 lanes 的代码同步进当前 lane。
|
||||
|
||||
### 缺口 3:merge_request 模型未接入执行主路径
|
||||
|
||||
系统里虽然有 `merge_requests` 表和 API,但当前并没有把它们接入 `leaderloop` / `taskexec` 的主执行链路。
|
||||
|
||||
### 缺口 4:lane 拆分策略过于宽松
|
||||
|
||||
当前 task DAG 会自动派生 lane,但不会约束:
|
||||
|
||||
- 哪些任务必须共用 lane
|
||||
- 哪些任务值得独立 lane
|
||||
- 哪些节点根本不需要独立 worktree
|
||||
|
||||
## 目标架构
|
||||
|
||||
建议引入两个新模块和一个新的持久化记录层。
|
||||
|
||||
### 模块 A:`lanesnapshot`
|
||||
|
||||
建议路径:
|
||||
|
||||
- `inbox/internal/app/lanesnapshot/`
|
||||
|
||||
职责:
|
||||
|
||||
- 检查 lane worktree 是否有代码变更
|
||||
- 过滤不应纳入版本控制的运行时垃圾
|
||||
- 生成 lane 的提交快照
|
||||
- 把最新提交记录回 lane 元数据
|
||||
|
||||
它不负责:
|
||||
|
||||
- 分配任务
|
||||
- merge 上游 lane
|
||||
- 启动容器
|
||||
|
||||
### 模块 B:`lanematerialize`
|
||||
|
||||
建议路径:
|
||||
|
||||
- `inbox/internal/app/lanematerialize/`
|
||||
|
||||
职责:
|
||||
|
||||
- 根据 task 依赖关系识别当前 task 的上游 lanes
|
||||
- 将上游 lane 的最新代码快照同步到当前 lane
|
||||
- 记录 merge / 物化结果
|
||||
- 冲突时产生结构化阻塞信息
|
||||
|
||||
它不负责:
|
||||
|
||||
- 选择哪个 task 该执行
|
||||
- 自动 replan
|
||||
- worker prompt 组装
|
||||
|
||||
### 模块 C:lane 同步记录
|
||||
|
||||
建议新增表:
|
||||
|
||||
- `lane_syncs`
|
||||
|
||||
建议字段:
|
||||
|
||||
- `id`
|
||||
- `workspace_id`
|
||||
- `topic_id`
|
||||
- `downstream_lane_id`
|
||||
- `upstream_lane_id`
|
||||
- `task_id`
|
||||
- `upstream_commit`
|
||||
- `merge_commit`
|
||||
- `status`
|
||||
- `error_message`
|
||||
- `created_at`
|
||||
- `updated_at`
|
||||
|
||||
用途:
|
||||
|
||||
- 保证物化过程可观测
|
||||
- 避免重复 merge 同一输入时缺乏依据
|
||||
- 为 dashboard / 调试 / 重试提供基础数据
|
||||
|
||||
## 数据模型改造
|
||||
|
||||
### 阶段性最小变更
|
||||
|
||||
在现有 `lanes` 表上新增字段:
|
||||
|
||||
- `head_commit TEXT NOT NULL DEFAULT ''`
|
||||
|
||||
说明:
|
||||
|
||||
- 领域名词与底层表名现在都使用 `lane / lanes`
|
||||
- 先在现有 `lanes` 表上扩字段,避免一次性大迁移
|
||||
|
||||
### 后续可选扩展
|
||||
|
||||
如需更强的可观测性,可继续新增:
|
||||
|
||||
- `last_materialized_at`
|
||||
- `last_materialized_commit`
|
||||
- `last_sync_error`
|
||||
|
||||
但这些不是第一阶段必需项。
|
||||
|
||||
## 关键执行点
|
||||
|
||||
### 1. 成功 task 完成后,自动生成 lane snapshot
|
||||
|
||||
建议接入点:
|
||||
|
||||
- `inbox/internal/app/taskexec/service.go`
|
||||
- `Complete(...)` 主路径
|
||||
|
||||
顺序建议:
|
||||
|
||||
1. worker 返回成功
|
||||
2. 宿主机确认 lane runtime 与 worktree 可访问
|
||||
3. `lanesnapshot` 检查并提交 worktree 代码
|
||||
4. 成功后才真正把 task 标成 `succeeded`
|
||||
5. 如果提交失败,则这次 run 视为失败或阻塞
|
||||
|
||||
原因:
|
||||
|
||||
- 一旦 task 已被标成成功,但代码并未形成稳定快照,下游 lane 仍然无法消费
|
||||
- 所以“成功完成 task”的定义应当包含“代码产物已稳定落盘到 git”
|
||||
|
||||
### 2. 下游 task 被 claim 前,先做 lane materialization
|
||||
|
||||
建议接入点:
|
||||
|
||||
- `inbox/internal/app/taskexec/service.go`
|
||||
- `ClaimNext(...)` 主路径
|
||||
|
||||
顺序建议:
|
||||
|
||||
1. 找到当前 lane 中下一个 ready task
|
||||
2. 识别其依赖 tasks
|
||||
3. 推导依赖 tasks 所属的上游 lanes
|
||||
4. `lanematerialize` 将上游 lane commits 同步到当前 lane
|
||||
5. 同步成功后再真正 claim task
|
||||
6. 如冲突,则不 claim,改为 `blocked`
|
||||
|
||||
原因:
|
||||
|
||||
- worker 启动时就应该处于“已拿到所有上游代码输入”的环境
|
||||
- 不要把 merge 责任甩给 worker
|
||||
|
||||
### 3. `workspaceruntime` 不做业务同步
|
||||
|
||||
`workspaceruntime` 继续只负责:
|
||||
|
||||
- ensure repository
|
||||
- ensure worktree
|
||||
- ensure container
|
||||
- stop container
|
||||
|
||||
不要把以下逻辑塞进去:
|
||||
|
||||
- 依赖 lanes 分析
|
||||
- 自动 commit
|
||||
- 自动 merge
|
||||
- 冲突策略判断
|
||||
|
||||
## 推荐 merge 策略
|
||||
|
||||
第一版建议使用最朴素、最可审计的策略:
|
||||
|
||||
- 上游 lane 产物必须先成为 git commit
|
||||
- 下游 lane 物化时使用显式 `git merge`
|
||||
- 保留 merge commit,不做 squash
|
||||
|
||||
原因:
|
||||
|
||||
- 依赖关系能在历史中直接看见
|
||||
- 调试时容易定位是哪条 lane 带进来的改动
|
||||
- 比起复制文件或 patch 应用,git merge 更符合当前 worktree 模型
|
||||
|
||||
### 合并顺序
|
||||
|
||||
建议按依赖拓扑顺序进行 merge。
|
||||
|
||||
以 `Integration And Verification` 为例,建议顺序:
|
||||
|
||||
1. `Foundation Setup`
|
||||
2. `Backend API`
|
||||
3. `Frontend App`
|
||||
|
||||
如果 `Backend` 和 `Frontend` 都已经是从 `Foundation` 分化出来的,并且各自分支历史完整,也可以只 merge 最终两个分支,由 git 自动通过共同祖先处理基础提交。
|
||||
|
||||
第一版不要求做最优优化,要求的是语义正确和行为稳定。
|
||||
|
||||
### 冲突处理
|
||||
|
||||
发生冲突时:
|
||||
|
||||
- 停止当前 materialization
|
||||
- 记录 `lane_syncs.status = failed`
|
||||
- task 标记为 `blocked`
|
||||
- lane 可标记为 `blocked`
|
||||
- 通过 message 或 task event 通知 leader
|
||||
|
||||
不要做以下行为:
|
||||
|
||||
- 自动硬解冲突
|
||||
- 静默 fallback 为“只读摘要继续执行”
|
||||
- 自动丢弃上游改动
|
||||
|
||||
## lane 拆分策略建议
|
||||
|
||||
除了代码流转,lane 数量本身也要更收敛。
|
||||
|
||||
### 应当独立 lane 的情况
|
||||
|
||||
- 明确并行价值高
|
||||
- 文件边界清晰
|
||||
- 预期实现时间较长
|
||||
- 失败隔离有意义
|
||||
- 产物可以作为其他 lane 的明确输入
|
||||
|
||||
### 应当共用 lane 的情况
|
||||
|
||||
- 前后两个 task 本质上是同一条连续实现链
|
||||
- 第二个 task 高度依赖第一个 task 的局部未抽象代码
|
||||
- 拆开后只会制造频繁 merge 和冲突
|
||||
|
||||
### 不应拥有独立代码 lane 的情况
|
||||
|
||||
- `milestone`
|
||||
- 纯 `gate`
|
||||
- 单纯汇报 / 审阅 / 总结型节点
|
||||
|
||||
## 分阶段实施
|
||||
|
||||
### 阶段 0:基线梳理与命名统一
|
||||
|
||||
目标:
|
||||
|
||||
- 明确以 `lane` 为统一术语
|
||||
- 建立当前缺口的自动化验证样例
|
||||
|
||||
实现内容:
|
||||
|
||||
- 文档统一使用 `lane`
|
||||
- 为 `todo-lane-smoke-2` 这类场景补回归测试描述
|
||||
- 梳理现有旧命名残留,不要求立刻全量改名
|
||||
|
||||
验收标准:
|
||||
|
||||
- 团队对外讨论统一使用 `lane`
|
||||
- 有一份可复现“下游 lane 看不到上游代码”的基线案例
|
||||
|
||||
### 阶段 1:lane snapshot 落地
|
||||
|
||||
目标:
|
||||
|
||||
- 成功的代码型 task 必须沉淀为 lane 分支上的 commit
|
||||
|
||||
实现内容:
|
||||
|
||||
- 在 `lanes` 表新增 `head_commit`
|
||||
- 新增 `lanesnapshot` 模块
|
||||
- 在 task 成功完成路径中自动:
|
||||
- 检查 worktree dirty 状态
|
||||
- 执行 `git add`
|
||||
- 执行 `git commit`
|
||||
- 写回 `head_commit`
|
||||
|
||||
建议约束:
|
||||
|
||||
- 只对 `execution` / `verification` 这类代码型 task 做 snapshot
|
||||
- `milestone` / `gate` 不生成代码提交
|
||||
|
||||
验收标准:
|
||||
|
||||
- `todo-lane-smoke-2` 中 `foundation` / `backend` / `frontend` 成功后,各自 lane 均有非空 `head_commit`
|
||||
- worktree 不再只停留在未提交改动
|
||||
|
||||
### 阶段 2:下游 lane materialization
|
||||
|
||||
目标:
|
||||
|
||||
- 下游 lane 能在 worker 执行前拿到上游 lane 的真实代码输入
|
||||
|
||||
实现内容:
|
||||
|
||||
- 新增 `lanematerialize` 模块
|
||||
- 新增 `lane_syncs` 表
|
||||
- 在 `ClaimNext(...)` 中对 candidate task 执行 materialization
|
||||
- materialization 成功后才 claim task
|
||||
|
||||
验收标准:
|
||||
|
||||
- `Integration And Verification` 在执行前能看到 `Backend API` 和 `Frontend App` 的真实代码
|
||||
- 回归时不再依赖 worker summary 重建实现
|
||||
|
||||
### 阶段 3:阻塞与 replan 闭环
|
||||
|
||||
目标:
|
||||
|
||||
- merge 冲突成为受控状态,而不是隐性失败
|
||||
|
||||
实现内容:
|
||||
|
||||
- 统一 materialization failure 到 `blocked`
|
||||
- 增加 task event / message,向 leader 报告冲突
|
||||
- leader 收到冲突后走 patch replan
|
||||
|
||||
验收标准:
|
||||
|
||||
- 冲突 topic 会稳定停在 `blocked`
|
||||
- leader 能基于冲突信息重新编排,而不是盲目新起 lanes
|
||||
|
||||
### 阶段 4:lane 拆分规则收紧
|
||||
|
||||
目标:
|
||||
|
||||
- 减少不必要的 lane / worktree / container 增生
|
||||
|
||||
实现内容:
|
||||
|
||||
- 调整 leader prompt 与 lane 派生规则
|
||||
- 倾向于把连续实现链保留在同一 lane
|
||||
- 仅在明确并行或集成汇聚点时拆新 lane
|
||||
- `milestone` / `gate` 不派生代码 lane
|
||||
|
||||
验收标准:
|
||||
|
||||
- 类似 `todo-lane-smoke-2` 的 topic 中,lane 数量与实际代码边界一致
|
||||
- 不再出现“为了一个收口任务额外生成空 lane”的情况
|
||||
|
||||
### 阶段 5:可观测性与回收策略
|
||||
|
||||
目标:
|
||||
|
||||
- 让 lane 运行时资源与代码同步状态都可追踪、可回收
|
||||
|
||||
实现内容:
|
||||
|
||||
- dashboard 展示:
|
||||
- `head_commit`
|
||||
- 最新 materialization 状态
|
||||
- lane sync 历史
|
||||
- topic 完成后可选执行:
|
||||
- 停止 lane runtime
|
||||
- 延迟回收容器
|
||||
- 延迟清理 worktree
|
||||
|
||||
说明:
|
||||
|
||||
- 本阶段是运维优化,不阻塞前四阶段主路径落地
|
||||
|
||||
验收标准:
|
||||
|
||||
- topic 完成后不再长期残留无意义运行中的 lane runtime
|
||||
- 调试时能直接看到 lane 的代码输入输出链路
|
||||
|
||||
## 需要修改的主要模块
|
||||
|
||||
### 必改
|
||||
|
||||
- `inbox/internal/app/taskexec/service.go`
|
||||
- `inbox/internal/store/sqlite/taskexec_store.go`
|
||||
- `inbox/internal/store/sqlite/migrations/`
|
||||
- `inbox/internal/domain/lane/`
|
||||
|
||||
### 新增建议
|
||||
|
||||
- `inbox/internal/app/lanesnapshot/`
|
||||
- `inbox/internal/app/lanematerialize/`
|
||||
- `inbox/internal/domain/lanesync/`
|
||||
- `inbox/internal/store/sqlite/lane_syncs_store.go`
|
||||
|
||||
### 暂不建议承载业务逻辑的模块
|
||||
|
||||
- `inbox/internal/app/workspaceruntime/`
|
||||
- `inbox/internal/httpapi/`
|
||||
- `inbox/internal/app/leaderloop/`
|
||||
|
||||
这些模块可以消费结果,不应承担主要 git 业务逻辑。
|
||||
|
||||
## 测试建议
|
||||
|
||||
### 单元测试
|
||||
|
||||
- snapshot 成功创建提交
|
||||
- worktree 无变化时不重复提交
|
||||
- materialization 能识别依赖 lanes
|
||||
- materialization 在冲突时稳定失败并写入 `blocked`
|
||||
|
||||
### 集成测试
|
||||
|
||||
以 `todo-lane-smoke-2` 类型流程验证:
|
||||
|
||||
1. `Foundation Setup` 成功后生成 commit
|
||||
2. `Backend API` / `Frontend App` 都从基础快照继续开发
|
||||
3. `Integration` 在启动前合并上游代码
|
||||
4. `milestone` 自动完成且不新建代码 lane
|
||||
|
||||
### 回归重点
|
||||
|
||||
- 不能破坏当前单 lane 串行执行
|
||||
- 不能让 `gate` / `milestone` 意外触发 git commit
|
||||
- 不能把未提交脏状态错误标记成“已可下游消费”
|
||||
|
||||
## 开放问题
|
||||
|
||||
### 1. 自动提交的粒度
|
||||
|
||||
第一版建议:
|
||||
|
||||
- 每个成功 task 最多生成一笔提交
|
||||
|
||||
不建议第一版支持:
|
||||
|
||||
- 一个 task 内自动切多笔提交
|
||||
|
||||
### 2. merge 粒度是按 task 还是按 lane
|
||||
|
||||
第一版建议按 `lane` 的最新成功快照物化。
|
||||
|
||||
原因:
|
||||
|
||||
- 实现简单
|
||||
- 与当前 runtime 粒度一致
|
||||
- 更符合“lane 是代码演进线”的模型
|
||||
|
||||
### 3. 是否必须使用 merge request 模型
|
||||
|
||||
第一版不必强制接入 `merge_requests`。
|
||||
|
||||
建议先把:
|
||||
|
||||
- 真实 commit 产物
|
||||
- lane materialization
|
||||
- 冲突阻塞
|
||||
|
||||
这三个核心闭环做完。
|
||||
|
||||
之后再决定是否把 `merge_requests` 升级成:
|
||||
|
||||
- lane 间同步记录
|
||||
- 人工审批面板
|
||||
- 最终 topic 合并机制
|
||||
|
||||
## 最小可上线版本
|
||||
|
||||
如果只做最小闭环,建议范围如下:
|
||||
|
||||
1. `lanes.head_commit`
|
||||
2. 成功 task 后自动提交
|
||||
3. `ClaimNext` 前 merge 上游 lane commits
|
||||
4. merge 冲突时标记 `blocked`
|
||||
|
||||
做到这一步,系统就已经从“摘要依赖”升级成“代码依赖”。
|
||||
|
||||
## 结论
|
||||
|
||||
这次改造的本质,不是“再加一个 merge 功能”,而是修正整个 lane 执行模型的语义:
|
||||
|
||||
- 上游 `lane` 的产物应该是代码快照
|
||||
- 下游 `lane` 的输入应该是上游代码状态
|
||||
- worker summary 应回归为编排证据,而不是代码同步手段
|
||||
|
||||
对 `todo-lane-smoke-2` 这样的 DAG 来说,这不是优化,而是让系统终于按自己宣称的依赖关系去工作。
|
||||
@@ -0,0 +1,460 @@
|
||||
# Leader DAG 化实施计划
|
||||
|
||||
本文档定义当前 `inbox v2` 从“leader 输出 chain/task 并即时执行”升级到“更稳定的 DAG planning / gating / replan”模型的落地方案。
|
||||
|
||||
目标不是照搬 Astro,而是吸收其中最有价值的五个机制,并严格适配我们现有架构:
|
||||
|
||||
- `leader` 运行在宿主机,内嵌于 `inbox server`
|
||||
- `worker` 运行在 per-chain 容器中
|
||||
- `topic / chain / task / dependency / workflow_run / message` 是现有运行时主模型
|
||||
- 不引入多机器调度,不引入 hosted control plane,不引入新的外部依赖
|
||||
|
||||
## 背景
|
||||
|
||||
最近几轮真实回归暴露出两个核心问题:
|
||||
|
||||
1. `leader` 的规划产物还不够稳定,更多是“即时创建 chain/task”,而不是明确的计划对象。
|
||||
2. `worker` 失败后的 replan 缺少约束,导致同一个 topic 里反复新建 chain,造成 worktree / container 增生。
|
||||
|
||||
这说明当前系统已经具备“可执行”的基本能力,但还缺少“可控规划”的中间层。
|
||||
|
||||
本计划把这层能力拆成五个阶段,按顺序落地。
|
||||
|
||||
## 总目标
|
||||
|
||||
实施完成后,系统应具备以下能力:
|
||||
|
||||
- `leader` 输出稳定的 planning schema,而不是松散文本
|
||||
- topic 在执行前先经过 gating,而不是盲目并发起 worker
|
||||
- 任务优先按 deliverable 和 batch 拆分,而不是隐式退化成角色链
|
||||
- `replan` 只能 patch 现有图,不能无限增生 chain
|
||||
- milestone 成为图中的一等节点,用于收口多分支结果
|
||||
|
||||
## 非目标
|
||||
|
||||
本计划不包含以下内容:
|
||||
|
||||
- 多机器 / 多 runner 调度
|
||||
- 容器资源感知调度
|
||||
- hosted dashboard / cloud relay
|
||||
- 通用 workflow DSL
|
||||
- 兼容旧 pool / discovery / fixed-role 路径
|
||||
|
||||
---
|
||||
|
||||
## 阶段 1:规划产物标准化
|
||||
|
||||
### 目标
|
||||
|
||||
让 `leader` 的输出从“只够当前 applyLeaderOutput 消费的最小 JSON”升级为稳定的 planning schema。
|
||||
|
||||
### 要解决的问题
|
||||
|
||||
- 当前 `leader` 输出主要服务于即时建链,不利于回放、对比、重规划
|
||||
- `reply_markdown`、`chains`、`tasks` 混在一起,缺少 plan 元信息
|
||||
- 缺少 task 的输入、产物、验证、批次、replan 策略等显式字段
|
||||
|
||||
### 产出
|
||||
|
||||
新增一个面向 `leader` 的 planning schema,建议至少包含:
|
||||
|
||||
- `plan_version`
|
||||
- `plan_summary_markdown`
|
||||
- `execution_mode`
|
||||
- `clarify`
|
||||
- `plan_only`
|
||||
- `plan_and_start`
|
||||
- `chains[]`
|
||||
- `key`
|
||||
- `name`
|
||||
- `purpose`
|
||||
- `reuse_strategy`
|
||||
- `tasks[]`
|
||||
- `key`
|
||||
- `chain_key`
|
||||
- `title`
|
||||
- `body_markdown`
|
||||
- `acceptance_markdown`
|
||||
- `deliverables[]`
|
||||
- `depends_on[]`
|
||||
- `verification`
|
||||
- `batch_key`
|
||||
- `replan_policy`
|
||||
- `milestones[]`
|
||||
- `start_nodes[]`
|
||||
- `leader_reply`
|
||||
|
||||
### 实现范围
|
||||
|
||||
- `inbox/internal/app/leaderloop/service.go`
|
||||
- 扩展 `leaderOutput` 结构
|
||||
- 更新 `leaderOutputSchema()`
|
||||
- 拆出 `plan` 相关校验函数
|
||||
- 如有必要,新增:
|
||||
- `inbox/internal/domain/plan/`
|
||||
- 或 `inbox/internal/domain/workflowplan/`
|
||||
|
||||
### 设计要求
|
||||
|
||||
- schema 必须可序列化进 `workflow_runs.config_snapshot_json` 或 `command_json`
|
||||
- `leader` 返回的 plan 必须可重放
|
||||
- plan 必须允许“仅规划不启动”
|
||||
|
||||
### 验收标准
|
||||
|
||||
- `leader` 输出可以表达:
|
||||
- 只澄清
|
||||
- 只规划
|
||||
- 规划并启动
|
||||
- 单元测试覆盖:
|
||||
- 完整 plan decode
|
||||
- 缺字段失败
|
||||
- 非法 dependency 失败
|
||||
- 非法 `start_nodes` 失败
|
||||
|
||||
### 风险
|
||||
|
||||
- 一次把字段做太多,导致 prompt 不稳定
|
||||
- schema 改动过大,影响现有 `taskexec` 和 dashboard 显示
|
||||
|
||||
### 收口策略
|
||||
|
||||
- 先新增字段,不立刻让 dashboard 全部消费
|
||||
- `leaderloop` 内部先把 schema 校验稳定,再逐步外显
|
||||
|
||||
---
|
||||
|
||||
## 阶段 2:前置 Gating 节点
|
||||
|
||||
### 目标
|
||||
|
||||
在真正启动 worker 之前,先通过一组 gating task 判断“是否具备执行条件”。
|
||||
|
||||
### 要解决的问题
|
||||
|
||||
- 当前 leader 规划后容易直接启动多个 chain
|
||||
- 一些基础条件没满足时,worker 只会重复失败
|
||||
- 失败后 leader 再次 replan,进一步放大噪音
|
||||
|
||||
### 典型 gating 场景
|
||||
|
||||
- 仓库结构是否存在
|
||||
- 运行时 provider / auth 是否可用
|
||||
- 基础 contract / API 边界是否已经明确
|
||||
- 必要目录 / package manager / root script 是否存在
|
||||
- topic 是否已具备足够信息,不需要继续澄清
|
||||
|
||||
### 产出
|
||||
|
||||
在 planning schema 中加入 gating 语义:
|
||||
|
||||
- `tasks[].kind`
|
||||
- `gate`
|
||||
- `execution`
|
||||
- `verification`
|
||||
- `milestone`
|
||||
- `tasks[].gate_policy`
|
||||
- `hard_stop`
|
||||
- `ask_user`
|
||||
- `leader_replan`
|
||||
|
||||
### 实现范围
|
||||
|
||||
- `leaderloop`
|
||||
- 在 `start_nodes` 解析时优先启动 gate task 所在 chain
|
||||
- `taskexec`
|
||||
- gate task 失败后,不自动放开后续依赖
|
||||
- `dashboard`
|
||||
- 在 chain/task board 上明确标记 gate 节点
|
||||
|
||||
### 设计要求
|
||||
|
||||
- gate 失败时,后续依赖节点保持 `draft` 或 `blocked`
|
||||
- leader 收到 gate 失败后,应优先 patch 计划,而不是起新图
|
||||
- gate task 的完成结果必须带结构化 failure reason
|
||||
|
||||
### 验收标准
|
||||
|
||||
- topic 首轮执行时,能先只启动 1 个 gating chain
|
||||
- gate 失败后,其余 chain 不启动
|
||||
- leader 能基于 gate failure 回复用户或 patch 任务
|
||||
|
||||
### 风险
|
||||
|
||||
- 如果 gating 太多,会让简单需求变慢
|
||||
|
||||
### 收口策略
|
||||
|
||||
- 只保留 2-3 类强 gating
|
||||
- 其它检查继续留在 worker 内部做普通失败
|
||||
|
||||
---
|
||||
|
||||
## 阶段 3:按 Deliverable 与 Batch 拆分
|
||||
|
||||
### 目标
|
||||
|
||||
让 leader 优先按产物边界拆 task,而不是退化成“前端链 / 后端链 / 基础链”这类松散角色链。
|
||||
|
||||
### 要解决的问题
|
||||
|
||||
- 当前 chain 名称仍然容易被 prompt 驱动成泛化角色链
|
||||
- 同一链上 task 颗粒度不稳定
|
||||
- 缺少批处理并行能力
|
||||
|
||||
### 产出
|
||||
|
||||
在 leader prompt 和 schema 中强化以下约束:
|
||||
|
||||
- task 必须显式描述最终产物
|
||||
- chain 只是执行容器,不是角色人设
|
||||
- 可以使用 `batch_key` 做批次并行
|
||||
|
||||
建议的拆分优先级:
|
||||
|
||||
1. 先按 deliverable 拆
|
||||
2. deliverable 太大时,再按 batch 拆
|
||||
3. 最后才落到实现域(frontend/backend/integration)
|
||||
|
||||
示例:
|
||||
|
||||
- `api-contract`
|
||||
- `backend-crud`
|
||||
- `frontend-list-create`
|
||||
- `frontend-edit-filter`
|
||||
- `integration-e2e`
|
||||
|
||||
而不是默认:
|
||||
|
||||
- `backend`
|
||||
- `frontend`
|
||||
- `foundation`
|
||||
|
||||
### 实现范围
|
||||
|
||||
- `leaderloop/buildLeaderPrompt`
|
||||
- 增加强约束,要求 chain/task 以产物命名
|
||||
- `leaderOutputSchema`
|
||||
- 增加 `deliverables[]` 和 `batch_key`
|
||||
- `dashboard`
|
||||
- 在 task 卡片中展示 deliverables 与 batch
|
||||
|
||||
### 设计要求
|
||||
|
||||
- 同一 batch 内的 task 应能独立并行
|
||||
- `deliverables[]` 应该能支持后续 verification 和 merge summary
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 相同需求多次规划时,chain/task 命名更稳定
|
||||
- leader 生成的任务里,至少 80% 有明确 deliverable 字段
|
||||
- 支持一个 topic 下存在“批量任务 + 聚合 milestone”
|
||||
|
||||
### 风险
|
||||
|
||||
- prompt 改得太死,影响 leader 灵活性
|
||||
|
||||
### 收口策略
|
||||
|
||||
- 不硬编码固定 chain 名称
|
||||
- 只强制“必须有 deliverable”,不强制唯一命名模板
|
||||
|
||||
---
|
||||
|
||||
## 阶段 4:Replan 只允许 Patch,不允许重建图
|
||||
|
||||
### 目标
|
||||
|
||||
把 replan 从“再创建一批 chain/task”改成“在同一张图上 patch 现有节点”。
|
||||
|
||||
### 要解决的问题
|
||||
|
||||
- 这次已经真实出现过:
|
||||
- worker 失败
|
||||
- leader 重规划
|
||||
- 同一 topic 新建 `chain-2`、`chain-3`、`chain-60`
|
||||
- worktree / container 爆炸增长
|
||||
|
||||
### 核心原则
|
||||
|
||||
- topic 进入 execution 后,禁止无边界新增 chain
|
||||
- replan 默认只能做:
|
||||
- 更新已有 chain 状态
|
||||
- 在已有 chain 下补 task
|
||||
- 调整 dependencies
|
||||
- 调整 `start_nodes`
|
||||
- 标记 chain/task 为 superseded / blocked / cancelled
|
||||
|
||||
只有在极少数场景下允许新增 chain,例如:
|
||||
|
||||
- 用户明确要求增加新的独立工作流分支
|
||||
- 原图中不存在可复用的产物链
|
||||
- leader 输出显式 `replan_mode = expand_graph`
|
||||
|
||||
即使允许扩图,也必须通过严格限制:
|
||||
|
||||
- topic 级 max chain count
|
||||
- replan iteration limit
|
||||
- leader 必须解释新增原因
|
||||
|
||||
### 产出
|
||||
|
||||
新增 replan 策略字段:
|
||||
|
||||
- `plan_mode`
|
||||
- `initial`
|
||||
- `patch`
|
||||
- `expand_graph`
|
||||
- `replan_reason`
|
||||
- `supersedes[]`
|
||||
|
||||
新增 topic 级保护:
|
||||
|
||||
- `max_chain_count`
|
||||
- `max_replan_count`
|
||||
|
||||
### 实现范围
|
||||
|
||||
- `leaderloop/applyLeaderOutput`
|
||||
- 默认复用已有 chain
|
||||
- 有 existing chains 时禁止无限新建
|
||||
- `taskexec`
|
||||
- worker failure 回传更结构化的失败原因
|
||||
- 可能需要:
|
||||
- `chains` / `tasks` 新状态,例如 `superseded`
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 同一 topic 上重复 worker 失败后,不再出现 chain 数量线性增长
|
||||
- topic 执行 5 次失败回执后,chain 总量仍保持稳定
|
||||
- 集成测试覆盖:
|
||||
- 初始计划
|
||||
- worker 失败
|
||||
- leader patch
|
||||
- 继续执行
|
||||
|
||||
### 风险
|
||||
|
||||
- patch 逻辑比“直接新增”更复杂
|
||||
- 旧 topic 的脏数据可能影响验证
|
||||
|
||||
### 收口策略
|
||||
|
||||
- 先在 `leaderloop` 内部做强保护
|
||||
- 旧 topic 不做兼容逻辑,直接清数据
|
||||
|
||||
---
|
||||
|
||||
## 阶段 5:Milestone 成为一等节点
|
||||
|
||||
### 目标
|
||||
|
||||
把 milestone 从隐式概念提升为图中的正式节点,用来汇聚多分支结果并决定下一步推进。
|
||||
|
||||
### 要解决的问题
|
||||
|
||||
- 当前多分支的收口主要靠 leader 自己看消息判断
|
||||
- 缺少“某几个 task 都完成后,再开始下一阶段”的正式表达
|
||||
|
||||
### 典型 milestone
|
||||
|
||||
- `Foundation Ready`
|
||||
- `API Contract Ready`
|
||||
- `Feature Complete`
|
||||
- `Ready for Integration`
|
||||
- `Ready for User Review`
|
||||
|
||||
### 产出
|
||||
|
||||
在 planning schema 中加入:
|
||||
|
||||
- `milestones[]`
|
||||
- `key`
|
||||
- `title`
|
||||
- `depends_on[]`
|
||||
- `summary_markdown`
|
||||
- milestone 可被 `start_nodes` 和后续 task 依赖引用
|
||||
|
||||
### 实现范围
|
||||
|
||||
- `leaderloop`
|
||||
- 允许创建 milestone 节点
|
||||
- 在依赖满足时将 milestone 标记为 ready/succeeded
|
||||
- `tasks` 或新表
|
||||
- 若不新增表,可先将 milestone 作为特殊 task kind 存储
|
||||
- `dashboard`
|
||||
- graph / board 中区分 milestone 与普通执行 task
|
||||
|
||||
### 设计要求
|
||||
|
||||
- milestone 不运行容器
|
||||
- milestone 只负责聚合前置状态
|
||||
- milestone 可以成为 integration / verification 的 gating 前提
|
||||
|
||||
### 验收标准
|
||||
|
||||
- 一条执行链中可见 milestone 节点
|
||||
- 多分支完成后 milestone 自动推进
|
||||
- leader 可以基于 milestone 状态决定是否继续启动 integration
|
||||
|
||||
### 风险
|
||||
|
||||
- 如果把 milestone 单独建表,会扩大 schema 变更面
|
||||
|
||||
### 收口策略
|
||||
|
||||
- 第一版先把 milestone 存成 `task.kind = milestone`
|
||||
- schema 稳定后再决定是否单独抽表
|
||||
|
||||
---
|
||||
|
||||
## 推荐实施顺序
|
||||
|
||||
严格按下面顺序推进,不要并行乱改:
|
||||
|
||||
1. 阶段 1:规划产物标准化
|
||||
2. 阶段 4:Replan 只允许 Patch
|
||||
3. 阶段 2:前置 Gating 节点
|
||||
4. 阶段 3:按 Deliverable 与 Batch 拆分
|
||||
5. 阶段 5:Milestone 一等节点
|
||||
|
||||
原因:
|
||||
|
||||
- 阶段 1 先固定 schema
|
||||
- 阶段 4 先止住增生风险
|
||||
- 阶段 2 再降低盲目执行
|
||||
- 阶段 3 再提高任务质量
|
||||
- 阶段 5 最后做图上的正式汇聚
|
||||
|
||||
## 每阶段的统一交付要求
|
||||
|
||||
每个阶段都必须同时完成:
|
||||
|
||||
- 领域模型改动
|
||||
- `leaderloop` 应用逻辑改动
|
||||
- 必要的 HTTP / dashboard 暴露
|
||||
- 单元测试
|
||||
- 至少一条真实或半真实回归路径
|
||||
|
||||
## 统一验收门槛
|
||||
|
||||
全部五阶段完成后,应满足:
|
||||
|
||||
- 同一 topic 不再出现失控 chain 增生
|
||||
- leader 输出稳定 plan schema
|
||||
- 执行前存在明确 gating
|
||||
- task 以 deliverable 为核心组织
|
||||
- 图中存在正式 milestone 节点
|
||||
- dashboard 能看出“计划 / 执行 / 收口”的结构
|
||||
|
||||
## 建议的实施文档拆分
|
||||
|
||||
后续真正进入实现时,建议在 `.omx/plans/` 或 `docs/` 下继续细分为:
|
||||
|
||||
- `phase-1-plan-schema.md`
|
||||
- `phase-2-gating.md`
|
||||
- `phase-3-deliverable-batching.md`
|
||||
- `phase-4-replan-patch-only.md`
|
||||
- `phase-5-milestones.md`
|
||||
|
||||
本文档作为总计划,不直接承担逐字段设计。
|
||||
@@ -0,0 +1,65 @@
|
||||
# Repository Modules
|
||||
|
||||
This repository is organized as a small monorepo with explicit module boundaries.
|
||||
|
||||
## Top-Level Modules
|
||||
|
||||
| Module | Path | Responsibility | Public interface | Test command |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Inbox host | `inbox/` | Control plane: CLI, HTTP API, agent dispatch, runtime storage | CLI commands and `/api/*` HTTP endpoints | `make test-inbox` |
|
||||
| Dashboard | `dashboard/` | Operations UI for the inbox host | Browser UI + calls to inbox HTTP API only | `make test-dashboard` |
|
||||
| Blog backend | `apps/blog/backend/` | Sample service API | HTTP endpoints exposed by Express | `make test-blog-backend` |
|
||||
| Blog frontend | `apps/blog/frontend/` | Sample client app | Browser UI + calls to blog backend HTTP API | `make test-blog-frontend` |
|
||||
| Blog E2E | `apps/blog/e2e/` | Black-box integration tests | Playwright against running frontend/backend | `make test-blog-e2e` |
|
||||
|
||||
## Dependency Rules
|
||||
|
||||
### Repository-level rules
|
||||
|
||||
- `dashboard/` must not import code from `inbox/`.
|
||||
- `apps/blog/frontend/` must not import code from `apps/blog/backend/`.
|
||||
- `apps/blog/e2e/` must treat frontend and backend as black boxes.
|
||||
- Runtime state, caches, worktrees, and local databases are generated artifacts and must not be committed.
|
||||
|
||||
### `inbox/` rules
|
||||
|
||||
The inbox module is the only place where repository control-plane logic should live.
|
||||
|
||||
- `cmd/inbox/` is the executable entrypoint only.
|
||||
- `internal/store/` owns persistence and schema details.
|
||||
- `internal/httpapi/` and `internal/httpservice/` own HTTP transport contracts and route wiring.
|
||||
- `internal/commands/`, `internal/cli/`, and `internal/web/` own CLI/Web command behavior.
|
||||
- `internal/*api`, `internal/*admin`, `internal/*flow`, and `internal/*bridge` packages are application services/adapters.
|
||||
- Top-level `inbox/*.go` files should stay as composition and compatibility wiring, not as the place where new domain logic grows.
|
||||
|
||||
Current workflow graph data lives in the inbox module as first-class runtime state:
|
||||
|
||||
- `leader` planning output persists to `workflow_runs.command_json` as structured `planning`
|
||||
- `chains` carry orchestration metadata such as `purpose`
|
||||
- `tasks` carry execution-graph metadata such as `kind`, `gate_policy`, `deliverables`, `verification_mode`, `batch_key`, and `replan_policy`
|
||||
- `task.kind = milestone` is the current milestone representation; milestone nodes do not dispatch workers
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Fast tests
|
||||
|
||||
Use module-local unit tests by default:
|
||||
|
||||
- `make test-inbox`
|
||||
- `make test-dashboard`
|
||||
- `make test-blog-backend`
|
||||
- `make test-blog-frontend`
|
||||
|
||||
### Browser/E2E tests
|
||||
|
||||
- `make test-dashboard-e2e`
|
||||
- `make test-blog-e2e`
|
||||
|
||||
The blog E2E suite starts backend and frontend via Playwright `webServer` configuration, so it can run independently from the rest of the repository once dependencies are installed.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Work in one module at a time.
|
||||
2. Run that module's tests before touching cross-module integration.
|
||||
3. Use HTTP or CLI contracts when crossing module boundaries.
|
||||
4. Prefer adding tests in the same module that owns the behavior.
|
||||
Reference in New Issue
Block a user