plan.md 5.44 KB

P0 地基 — Graph Agent 架构任务拆分

对应 docs/system-design/27-graph-agent-architecture.md 的 Phase P0。目标:只加不改——新建三张表,把现有数据原样导入作为种子数据并校验行数,完全不动 company-service.js 现有的 hire/copy 执行路径。这是 P1(虚拟引用改造)能安全推进的前提:先有一份可信、经过校验的镜像数据在 DB 里,再去改代码。

Context

两轮只读调研确认了关键事实:

  • 现有三个 sqlite 库(skills.sqlite/benchmark_logs.sqlite/users.sqlite)都遵循同一套手写约定:server/services/*-db.js 里 new Database() + WAL + CREATE TABLE IF NOT EXISTS(无迁移文件、无版本追踪),snake_case 列名。没有 :memory: 测试,测试用临时文件 + env 变量覆盖 DB 路径 + 清 require 缓存(server/tests/unit/skill-db.test.js 是标准范式)。benchmark-db.js 声明了 env override 但实际没读,是个已知的潜在 bug,新代码要避免重蹈。
  • system/agents/ 有 11 个目录,其中 system/agents/templates/ 是遗留杂物、不是真 agent,必须过滤掉(真实 agent 数 = 10)。
  • system/templates/ 有 34 个目录,但 _registry.json(数组)只覆盖 9 个(ceo/qa-judge/base/6 个 devloop-*)——目录扫描才是数据源头,registry 只用来补充可选的 benchmark 元数据,其余 25 个模板要容忍没有 config.json(如 ceo/ 只有 plan.md+todo.md)。
  • data/companies/ 目前只有一家真实公司 idearun,company.json.agents 是 6 个角色名字符串的扁平数组:youtube-crawler/evolver-youtube-crawler 能对上 system/agents/ 里的全局 agent,另外 4 个(claude-youtube-skills/trend-scout-global/content-selector/idearuncreate)在 global/template 里都找不到对应目录——这些是公司专属训练出来的实例,是"company-scoped system agent"这个概念在真实数据里的第一批样本。
  • company-service.js 的 hire(189)/scaffoldNewAgent(241)/depositTemplate(294)/hireWithTraining(381)/_copyTemplate(621)/_injectCompanyContext(667) 六个函数行号已核实无漂移,P0 全程不动这个文件。

新增文件

  • server/services/graph-db.js —— 新 sqlite 库 data/graph.sqlite,照抄 skill-db.js/user-db.js 的样板:fs.mkdirSync 保证目录存在 → new Database(DB_PATH) → journal_mode=WAL + foreign_keys=ON → lazy singleton getDb()。支持 GRAPH_DB_PATH env 覆盖,且要确保代码真的读了这个变量。
  • server/services/graph-seed-service.js —— 导出 seedGlobalAgents() / seedTemplates() / seedCompanyAgents() / verifyCounts(),供脚本和测试复用。
  • scripts/graph-seed.js —— 薄 CLI 入口,依次调用上面四个函数并打印汇总报告,风格参照现有 scripts/sync-skills.js。
  • package.json 加一条 "graph:seed": "node scripts/graph-seed.js"。
  • server/tests/unit/graph-db.test.js —— 照抄 skill-db.test.js 的临时文件 + env 覆盖 + 清 require 缓存范式。

Schema

CREATE TABLE IF NOT EXISTS system_agents (
  id               TEXT PRIMARY KEY,        -- 就是目录名,如 'master'/'ceo'/'claude-youtube-skills'
  name             TEXT NOT NULL,
  scope            TEXT NOT NULL CHECK (scope IN ('public','company')),
  owner_company_id TEXT,
  source_kind      TEXT NOT NULL CHECK (source_kind IN ('global_agent','template','company_hired')),
  legacy_path      TEXT NOT NULL,           -- 当前真实所在目录,如 'system/agents/master'
  status           TEXT NOT NULL DEFAULT 'active',
  benchmark_score  REAL,
  created_at       TEXT NOT NULL,
  updated_at       TEXT NOT NULL
);

CREATE TABLE IF NOT EXISTS org_graph_nodes (
  id               INTEGER PRIMARY KEY AUTOINCREMENT,
  company_id       TEXT NOT NULL,
  system_agent_id  TEXT NOT NULL REFERENCES system_agents(id),
  role_name        TEXT NOT NULL,
  created_at       TEXT NOT NULL
);

CREATE TABLE IF NOT EXISTS org_graph_edges (
  id               INTEGER PRIMARY KEY AUTOINCREMENT,
  company_id       TEXT NOT NULL,
  from_node_id     INTEGER NOT NULL REFERENCES org_graph_nodes(id),
  to_node_id       INTEGER NOT NULL REFERENCES org_graph_nodes(id),
  relation_type    TEXT NOT NULL
);

相对设计文档(27 号)草稿的两处调整:

  1. system_agents.id 用 TEXT PRIMARY KEY = 目录名,不用自增代理键——后续阶段要靠这个 id 反查文件系统路径,代理键只会多一层无意义的间接。
  2. 新增 source_kind + legacy_path 两列——P0 明确不做目录搬迁(三种来源现在物理上分散在三个不同地方),没有这两列种子数据就"没有指针",没法在 P1 真正切换执行路径时定位到原文件。

org_graph_nodes/org_graph_edges 沿用仓库现有的自增整数主键惯例,暂不需要对外暴露的字符串 ID(要到 P2/P3 才会被外部引用)。

验证方式

  1. npm run test:unit —— 新增的 graph-db.test.js 通过,现有测试无回归
  2. npm run graph:seed —— 在真实仓库数据上跑,人工核对输出的行数汇总(10 / 34 / 6,见下方任务列表)
  3. sqlite3 data/graph.sqlite ".schema" —— 人工确认三张表结构与上面 SQL 一致
  4. git diff --stat —— 确认这一阶段的改动只新增文件,没有改动 company-service.js/agent-manager.js/prompt-builder.js 任何一行

任务清单见 todo.md。