# 01-M-模型设计 数据落地原则(继承架构文档 7.3 节):Artifact、代码、Skill、Memory、Agent 人设文件全部纳入 Git 仓库版本化;执行记录(状态转移、reflection 记录)独立于 Git,落结构化存储(MVP 阶段可用 SQLite/本地文件型数据库,不强制引入外部数据库服务)。 **新增原则(架构文档第 13 节)**:目标项目是独立于 graphlemon 平台自身的代码空间。`project.target_folder_path` 指向的文件夹拥有自己的 Git 仓库;graphlemon 平台自己的结构化存储(本文件描述的全部实体)与目标项目的 Git 历史是两套独立的持久化,前者只是引用后者的文件路径,不托管目标项目的代码本身。 ## 1.0 实体:`project` **目的**:一个目标项目 = 一个独立代码空间(用户选择的本地文件夹)。MVP 阶段只有一个 `active` 项目,但数据模型按多项目设计以便后续扩展。 - `project_id` string,pk(UUID) - `name` string,not null - `target_folder_path` string,not null,unique —— 本地绝对路径 - `has_git_repo` boolean,not null —— 创建项目时校验;若原文件夹不是 Git 仓库,创建流程需询问是否代为初始化 - `graphlemon_subdir_initialized` boolean,not null,default false —— 是否已在目标文件夹内创建 `.graphlemon/` 子目录(见架构文档 13.2 节目录约定) - `status` enum,not null —— `active`\|`archived` - `created_at` timestamp - 唯一约束:`target_folder_path`(同一文件夹不能重复创建为两个项目) - 并发/幂等:创建项目时若路径已存在对应 `project` 记录,直接返回已有记录而非报错(幂等创建) ## 1.1 实体:`org_graph_definition` **目的**:Org Graph 的静态定义(Planner→Coder→Validator 三节点 + 回退边),人工维护,变更需人工评审,不由系统自主修改。 - `graph_id` string,pk,如 `dev-organizer` - `version` string,not null(Git tag/commit 引用) - `nodes` json,not null —— 数组,每项 `{ node_id, role, agent_profile_ref }` - `edges` json,not null —— 数组,每项 `{ from, to, condition }`(如 `validator→coder` 的 `condition: route==fast_lane`) - `file_path` string,not null —— 指向 `org/dev-organizer.graph.yaml` 的相对路径 - 状态集合:`draft`、`active`、`deprecated` - 变更约束:仅人工提交 + 评审后的 Git commit 可以更新此实体,系统不得自主写入 ## 1.2 实体:`task` **目的**:任务队列条目,替代原飞书多维表格的需求表/Bug 表(架构文档 12.1 节已确认)。 - `task_id` string,pk(UUID) - `project_id` string,not null,fk → `project.project_id` - `goal_text` string,not null —— 原始 Goal 描述或 Validator 回传的 bug 任务描述 - `task_type` enum,not null —— `goal` \| `bug_fix` - `origin_ref` string,nullable —— 若 `task_type=bug_fix`,指向来源 `bug_record.bug_id` - `created_via` enum,not null,default `api` —— `api`\|`human_console`(区分是控制台人工提出还是程序化创建,用于审计) - `status` string,not null —— 状态集合见 04-P 的 `p_org_task_lifecycle` - `route` enum,nullable —— `fast_lane` \| `full_replan`(仅 `bug_fix` 类型需要,由 Validator 判定写入) - `loop_round` int,not null,default 0 —— 当前 Org-level Loop 已执行轮次 - `blocked_reason` string,nullable —— 达到轮次上限或预算超限时的原因说明 - `assigned_org_node` string,not null,fk —— 当前所处 Org Graph 节点(`planner`\|`coder`\|`validator`) - `created_at` / `updated_at` timestamp - 索引:`status`、`assigned_org_node`、`project_id`(用于调度器扫描和控制台按项目筛选) - 唯一约束:无(同一 Goal 可能因 loop 产生多条 `bug_fix` 类型的派生 task,但需通过 `origin_ref` 追溯血缘) - 并发/幂等:调度器认领 task 需用乐观锁(`status` 字段的 CAS 更新),避免并发调度重复认领 ## 1.3 实体:`work_graph_run` **目的**:某个 Org Agent 针对某个 `task` 的一次 Work Graph 执行实例(动态生成、每次任务重新规划)。 - `run_id` string,pk(UUID) - `task_id` string,not null,fk → `task.task_id` - `org_node` string,not null —— `planner`\|`coder`\|`validator` - `graph_manifest` json,not null —— 本次生成的 Work Graph 结构化定义(节点、边、fan-out/fan-in 分组、loop 规则),对应课程里的 `sdd_exec_graph_manifest.json` 风格 - **补充说明(2026-07-30,回应"task 层级关系看不出来"的核对)**:`org_node=coder` 的这份 `graph_manifest` 就是架构文档 §6.2 所说的"to-do list"本身——to-do 项 = `graph_manifest` 里的节点,to-do 项之间的先后/并行依赖 = 节点间的边和 fan-out/fan-in 分组。不新建独立的 `todolist` 实体或 `artifact_type`,避免同一份数据有两个来源。层级关系是:`project → task(一个 goal = 一个 task = 一个 Org Graph)→ work_graph_run(按 org_node 各一次)→ graph_manifest 定义的 to-do/节点树 → work_node_execution → execution_log_file`。控制台侧 `v_task_detail` 需要把这棵树画出来(见 02-V §2.6 更新),而不是平铺展示 Work Node。 - `orchestration_script_ref` string,nullable —— 若走 Claude Code 原生动态工作流(架构文档 10.1 节方案 A),指向保存的编排脚本路径(`.claude/workflows/.js`) - `status` string,not null —— 状态集合见 04-P 的 `p_work_graph_execution` - `started_at` / `completed_at` timestamp - `result_artifact_refs` json,nullable —— 本次运行产出的 `artifact.artifact_id` 列表 - 生命周期:`planning → running → merging → verifying → done|failed|blocked` - 并发/幂等:同一 `task_id + org_node` 同一时刻只允许一个 `active` 状态的 `work_graph_run`(唯一约束:`(task_id, org_node) WHERE status IN ('planning','running','merging','verifying')`) ## 1.4 实体:`work_node_execution` **目的**:`work_graph_run` 内每个 Work Node 的执行记录,对应课程"给每个节点一个契约"。 - `node_exec_id` string,pk - `run_id` string,not null,fk → `work_graph_run.run_id` - `node_id` string,not null —— 在 `graph_manifest` 中的节点标识 - `subagent_type` string,not null —— 绑定的 Subagent 类型 - `skill_ref` string,not null,fk → `skill.skill_id` - `input_schema_ref` / `output_schema_ref` string,not null —— JSON Schema 引用,强制校验(课程"给每个节点一个契约"的落地) - `input_payload` json,not null - `output_payload` json,nullable —— 校验失败时为 null,触发重试 - `model_tier` enum,not null,default `standard` —— `cheap`\|`standard`\|`premium`(对应课程"按节点分层选模型") - `status` string,not null —— `pending`\|`running`\|`reflecting`\|`retrying`\|`waiting_for_quota`\|`blocked`\|`done`\|`failed`(`waiting_for_quota` 新增,2026-07-29,见下方与 03-C 3.6/3.5 节) - `retry_count` int,not null,default 0 - `reflection_notes` json,nullable - `git_worktree_ref` string,nullable —— 若节点涉及并行写代码,记录隔离用的 git worktree 路径(对应课程"节点隔离") - `quota_wait_started_at` timestamp,nullable —— 首次检测到 Claude Code plan 额度耗尽的时间,仅 `status=waiting_for_quota` 时有值,用于计算是否超过等待上限 - `quota_limit_type` enum,nullable —— `session`\|`weekly`\|`opus`,从 `claude -p` 报错文本判断额度类型(新增,2026-07-29,见 03-C 3.6 节) - 并发/幂等:`output_payload` 写入前必须通过 `output_schema_ref` 校验;校验失败自动重试,`retry_count` 达上限后置为 `failed` 并冒泡到 `work_graph_run` 层 - **额度等待语义(新增,2026-07-29)**:`waiting_for_quota` 不是失败态,是自愈型阻塞——`retry_count` 不计入这类重试(避免和真实的 schema 校验失败重试混淆),退避轮询策略和超时兜底见 03-C 3.6 节 ## 1.5 实体:`artifact` **目的**:BRD/PRD/SDD/Benchmark/测试用例集/Bug 记录等结构化产物,版本化、有血缘。 - `artifact_id` string,pk - `artifact_type` enum,not null —— `brd`\|`prd`\|`sdd`\|`benchmark`\|`bug_record`\|`code_diff`\|`test_report` - `task_id` string,not null,fk → `task.task_id` - `produced_by_run_id` string,not null,fk → `work_graph_run.run_id` - `file_path` string,not null —— 路径语义按 `artifact_type` 区分:`brd`/`prd`/`sdd`/`benchmark`/`bug_record` 落在目标项目 `/.graphlemon/runs//...`(架构文档 13.2 节);`code_diff`/`test_report` 落在目标项目自身源码目录内,路径由 Coder 按目标项目既有约定决定,不强制结构 - `git_commit_sha` string,not null —— 对应**目标项目自身仓库**的 Git 提交(不是 graphlemon 平台仓库的提交) - `depends_on_artifact_ids` json,nullable —— 血缘引用(如 `sdd` 依赖某版本 `prd`) - `validation_status` enum,not null,default `pending` —— `pending`\|`passed`\|`failed` - `created_at` timestamp - 唯一约束:`(task_id, artifact_type, git_commit_sha)` - 迁移/回滚约束:`artifact` 一旦写入不可变更(immutable),修订产生新记录并更新 `depends_on_artifact_ids` 血缘链,不做原地更新 ## 1.6 实体:`bug_record` **目的**:结构化问题记录(`artifact_type=bug_record` 的强类型展开),来源可以是 Validator 自动生成,也可以是人在控制台手工反馈(架构文档第 13 节新增诉求)。 - `bug_id` string,pk - `task_id` string,nullable,fk —— 人工反馈时可能尚未关联具体 task(先建 bug_record,再由 Validator triage 后创建/关联 task) - `source` enum,not null —— `validator`\|`human` - `reported_by` string,nullable —— `source=human` 时记录操作人标识 - `description` string,not null - `repro_steps` string,nullable —— `source=human` 时允许先留空,Validator triage 阶段补齐 - `root_cause_category` enum,nullable —— `planning`\|`coder`\|`skill_defect`\|`core_engine`(新增,2026-07-30,见 05 节 §5.8:覆盖 `.claude/agents/*.md` 身份文件变更、Graph Engine 调度器/执行器抽象层核心逻辑变更、01-M 自身数据库 schema 变更三类 self-target 场景,命中时 `c_org_loop_route` 路由到 `p_deploy_supervisor_blue_green` 而非常规 `fast_lane`/`full_replan`,见 1.15/1.16 节、03-C、04-P);`source=human` 且尚未 triage 时为 null - `root_cause_detail` string,nullable —— 具体归因说明(引用具体 SDD 章节/Coder 实现记录/Skill ID);`source=validator` 时必填,`source=human` 待 triage 完成后必填 - `related_artifact_ids` json,nullable —— 关联的原始 Artifact 版本;`source=human` 提交时可能为空 - `suggested_route` enum,nullable —— `fast_lane`\|`full_replan`;triage 完成前为 null - `skill_iteration_suggestion_id` string,nullable,fk → `skill_iteration.iteration_id` - `status` enum,not null —— `open`\|`triaging`\|`routed`\|`resolved`(`source=human` 的记录初始态为 `open`,Validator 认领后转 `triaging`) - 并发/幂等:同一 `task_id` 允许多条 `bug_record`(一次验证可能发现多个问题),互不影响 ## 1.7 实体:`skill` **目的**:Skill 库条目,Git 版本化,可被 Validator 触发自主迭代。 - `skill_id` string,pk(如 `write-sdd`、`code-task-development`、`qa-task-validation`) - `owner_org_node` string,not null —— `planner`\|`coder`\|`validator` - `file_path` string,not null —— `skills//` 目录 - `current_git_commit_sha` string,not null - `source` enum,not null —— `migrated_from_hermes`\|`new`\|`auto_iterated` - `migrated_from_profile` string,nullable —— 若来自本地 Hermes profile 迁移,记录来源(`code`\|`planning`\|`qa`) - 状态集合:`active`\|`archived` ## 1.8 实体:`skill_iteration` **目的**:Skill 自主迭代的变更记录(架构文档 8 节决策 1:允许自主改写并立即生效,但每次变更必须是独立 Git 提交)。 - `iteration_id` string,pk - `skill_id` string,not null,fk → `skill.skill_id` - `triggered_by_bug_id` string,not null,fk → `bug_record.bug_id` - `before_git_commit_sha` / `after_git_commit_sha` string,not null - `change_summary` string,not null - `applied_at` timestamp - `rollback_of_iteration_id` string,nullable —— 若本次是对某次迭代的回滚 - 约束:每条记录对应一次独立 Git commit,commit message 必须包含 `triggered_by_bug_id` ## 1.9 实体:`agent_profile` **目的**:Org Agent 的人设与运行契约文件元数据(迁移自本地 Hermes profile 的 `SOUL.md`/`AGENTS.md`)。 - `org_node` string,pk —— `planner`\|`coder`\|`validator` - `soul_file_path` string,not null —— `agents//SOUL.md` - `agents_file_path` string,nullable —— 仅 `validator` 有 `AGENTS.md` - `migrated_from_profile` string,not null —— `planning`\|`code`\|`qa` - `current_git_commit_sha` string,not null ## 1.10 实体:`budget_guardrail_config` **目的**:预算/额度护栏配置(架构文档 7.5 节,双层护栏之一:手工配置层)。 - `config_id` string,pk,default `default` - `scope` enum,not null —— `global`\|`per_task`\|`per_day` - `limit_type` enum,not null —— `token_count`\|`call_count` - `limit_value` int,not null - `current_usage` int,not null,default 0 - `on_exceed_action` enum,not null,default `pause_and_notify` - `updated_by` string,not null —— 管理后台操作人 - `updated_at` timestamp ## 1.11 实体:`org_concurrency_config` **目的**:多 Goal 并发数配置(架构文档 8 节决策 5,MVP 默认 1,管理后台可调)。 - `config_id` string,pk,default `default` - `max_concurrent_goals` int,not null,default 1 - `updated_by` string,not null - `updated_at` timestamp ## 1.12 实体:`execution_event` **目的**:架构文档第 13 节新增——控制台实时看板的唯一数据源。所有状态变化在写入各自实体的同时追加一条事件记录,既用于 WebSocket 推送,也用于"检查过程"页面回放历史时间线,避免另建一套单独的日志系统。 - `event_id` string,pk(单调递增或 ULID,保证可排序) - `project_id` string,not null,fk → `project.project_id` - `task_id` string,nullable,fk - `run_id` string,nullable,fk → `work_graph_run.run_id` - `node_exec_id` string,nullable,fk → `work_node_execution.node_exec_id` - `event_type` enum,not null —— `task_status_changed`\|`node_status_changed`\|`artifact_created`\|`bug_recorded`\|`loop_routed`\|`budget_updated`\|`skill_iterated` - `payload` json,not null —— 事件详情(如 `{from_status, to_status}`) - `created_at` timestamp,not null,index - 索引:`(project_id, created_at)`(看板按项目拉取时间线)、`(task_id, created_at)`(任务详情页时间线) - 约束:`execution_event` 只追加不更新不删除(append-only),是审计和实时推送的唯一事实源;写入 `execution_event` 与写入对应业务实体(如 `task.status`)需在同一事务内完成,避免看板显示与实际状态不一致 - 原始执行会话日志(Claude Code ACP 的完整对话记录)**不**存入本表,本表只记录结构化摘要事件;原始日志存储见 1.13 `execution_log_file`,`event_type` 新增 `log_appended` 用于驱动控制台实时滚动日志(见下方实体更新) (`event_type` 枚举补充:`task_status_changed`\|`node_status_changed`\|`artifact_created`\|`bug_recorded`\|`loop_routed`\|`budget_updated`\|`skill_iterated`\|`log_appended`\|`quota_wait_started`(新增,2026-07-29,见 03-C 3.6 节额度等待重试语义)) ## 1.13 实体:`execution_log_file` **目的**:架构文档第 13.1 节决策 4——Work Node 执行的原始会话日志本地落盘,控制台内直接可看,与 Git 版本化的 Artifact/Skill 是两套不同生命周期的存储。 - `log_file_id` string,pk - `node_exec_id` string,not null,unique,fk → `work_node_execution.node_exec_id` —— 一个 Work Node 执行对应一个日志文件 - `project_id` string,not null,fk → `project.project_id` - `file_path` string,not null —— graphlemon 平台本地日志目录下的路径,如 `~/.graphlemon/logs////.jsonl`(不在任何 Git 仓库内) - `format` enum,not null —— `jsonl`\|`raw_text`(取决于底层执行引擎的会话记录格式) - `size_bytes` int,not null,default 0 —— 执行过程中增量更新 - `status` enum,not null —— `active`(写入中)\|`closed`(节点执行结束,日志文件不再追加)\|`purged`(已被清理任务删除) - `created_at` timestamp - `purged_at` timestamp,nullable - 索引:`node_exec_id`(唯一)、`project_id` - 约束:日志文件由执行器抽象层(架构文档 7.2 节)在 Work Node 执行期间流式追加写入,每次追加同时写一条 `execution_event(event_type=log_appended)` 驱动控制台实时滚动;`status=purged` 后 `file_path` 指向的物理文件已被删除,但记录本身保留作审计(不物理删除 `execution_log_file` 行,只标记状态),避免"日志曾经存在过"这件事本身也查不到 ## 1.14 实体:`log_retention_config` **目的**:日志清理策略配置,对应用户诉求"定时清理就好"。 - `config_id` string,pk,default `default` - `retention_days` int,not null,default 14 —— 超过该天数的 `execution_log_file`(`status=closed`)会被清理任务标记为 `purged` 并删除物理文件 - `max_total_size_mb` int,nullable —— 可选的总大小上限,超过时按最旧优先清理(即使未到 `retention_days`) - `updated_by` string,not null - `updated_at` timestamp ## 1.15 实体:`deployment`(PH5 新增,2026-07-30,见 `docs/done/supervisor-auto-rollback-design.md`) **目的**:Deploy Supervisor 对 graphlemon 自身(self-target 场景)执行一次蓝绿部署的记录,覆盖从候选实例拉起到最终 `finalized`/`rolled_back`/`blocked_pending_human` 的完整生命周期。Deploy Supervisor 是独立于 Graph Engine 之外的进程,不要与架构文档里"Supervisor(调度子 Agent,Coder Work Graph 内部监控节点)"混淆,两者是完全不同的概念(详见 `supervisor-auto-rollback-design.md` 开头命名说明)。 - `deployment_id` string,pk(UUID) - `git_commit_hash` string,not null —— 本次候选版本对应的 graphlemon 自身仓库 commit - `previous_commit_hash` string,not null —— 回滚目标,取上一条 `status=finalized` 的 `deployment.git_commit_hash` - `status` enum,not null —— `staged`\|`candidate_starting`\|`health_check_running`\|`health_check_passed`\|`health_check_failed`\|`cutover_in_progress`\|`live`\|`monitoring`\|`anomaly_detected`\|`rollback_in_progress`\|`rolled_back`\|`rollback_failed`\|`blocked_pending_human`\|`monitoring_window_clean`\|`finalized`(完整状态转移见 04-P `p_deploy_supervisor_blue_green`) - `candidate_port` int,nullable —— 健康检查阶段候选实例监听的临时端口 - `candidate_db_path` string,nullable —— 一次性生产库副本路径,健康检查结束后清理 - `started_at` / `cutover_at` / `monitoring_closed_at` / `rollback_at` timestamp,nullable - `rollback_reason` string,nullable —— 触发回滚的具体信号快照(哪个 `signal_type`、哪次采样、什么值),或"回滚本身失败"的原因说明 - `previous_instance_dir` string,not null —— 上一个已知良好版本的 checkout 目录,在本次 deployment 监控窗口正常关闭(`finalized`)前不允许清理 - 约束:同一时刻 graphlemon 自身仓库只允许一条处于非终态(不在 `finalized`\|`rolled_back`\|`blocked_pending_human`)的 `deployment` 记录,避免并发蓝绿部署互相干扰 ## 1.16 实体:`deploy_health_signal`(PH5 新增,2026-07-30,见 `docs/done/supervisor-auto-rollback-design.md`) **目的**:`deployment` 生命周期内每次健康检查/监控采样的记录,全部是确定性判断结果,不涉及任何 LLM 判断。 - `signal_id` string,pk - `deployment_id` string,not null,fk → `deployment.deployment_id` - `sampled_at` timestamp,not null - `signal_type` enum,not null —— `process_alive`\|`http_health`\|`canary_task`\|`validator_approval_rate` - `status` enum,not null —— `ok`\|`degraded`\|`fail` - `detail` string,nullable —— 供人工事后排查的具体数值/日志摘录,不参与自动判断逻辑 - 索引:`(deployment_id, sampled_at)`(按部署拉取信号时间线) - 约束:`deploy_health_signal` 只追加不更新不删除(append-only),与 `execution_event` 的审计哲学一致