# P0 任务清单 依赖顺序:T0 阻塞全部 → T1/T2 → checkpoint → T3 → T4 → T5 - [x] **T0 — 建表 + DB 模块** - 产出:`server/services/graph-db.js` + `server/tests/unit/graph-db.test.js` - 验收:测试断言三张表通过 `sqlite_master` 查询存在;断言设置 `GRAPH_DB_PATH` 后确实写到了别的文件(回归防 benchmark-db.js 那种"声明了但没读"的 bug) - [x] **T1 — 导入 `system/agents/` → `system_agents`** - 扫描 `system/agents/*`,过滤掉没有 `agent.md` 的目录(排除 `templates/` 杂物),逐个插入 `scope='public', owner_company_id=NULL, source_kind='global_agent'` - 验收:`SELECT COUNT(*) WHERE source_kind='global_agent'` = 10;脚本可重复执行不产生重复行(`INSERT OR IGNORE`/upsert on id) - [x] **T2 — 导入 `system/templates/` → `system_agents`** - 扫描 34 个模板目录,用 `_registry.json` 按 id 匹配补充 `benchmark_score`(只有 9 个能匹配上,其余留 NULL),容忍缺失 `config.json` - 验收:`COUNT(*) WHERE source_kind='template'` = 34;抽查 9 个 registry 覆盖到的条目 `benchmark_score` 非空,其余 25 个为 NULL - **实际结果(见执行报告)**:真实目录是 39 个(非文档所写的 34),其中 6 个与 `system/agents/*` 目录同名(`agent-creator`/`digester`/`evolver`/`evolver-youtube-crawler`/`hunter`/`innovator`)——已加冲突保护跳过写入,避免污染 T1 的 global_agent 行,故 `COUNT(*) WHERE source_kind='template'` = 33;registry 9 个 id 全部匹配上,但其中 6 个 devloop-* 在 registry 里本身 `benchmarkScore` 就是 `null`,故非空的只有 `ceo`(97)/`qa-judge`(95)/`base`(90) 3 个,其余(含 6 个 devloop-* 匹配项)均为 NULL - [ ] **checkpoint** — T0-T2 落地后手动跑一遍 `graph:seed`,人工看一眼种子数据是否符合预期,再继续 T3 - [x] **T3 — 导入 `data/companies/*/company.json.agents[]` → `system_agents` + `org_graph_nodes`** - 已有同名 `system_agents` 行(来自 T1/T2)→ 只建 `org_graph_nodes` 指过去;没有 → 新建 `scope='company', owner_company_id=, source_kind='company_hired'` 行,再建 `org_graph_nodes`。`org_graph_edges` 本阶段留空(`company.json` 目前没有汇报关系数据,是预期状态) - 验收:对真实的 `idearun`,`org_graph_nodes` 恰好 6 行;其中 2 行引用已存在的行(`youtube-crawler`/`evolver-youtube-crawler`),4 行触发新建 `scope='company'` 记录 - **实际结果(见执行报告)**:`org_graph_nodes` 行数对得上(6 行),但引用/新建的拆分与本条原始预期不一致——亲自核对 `data/companies/idearun/company.json` 与 `system/agents/`、`system/templates/` 目录后发现:`idearun.agents[]` 的 6 个角色名(`claude-youtube-skills`/`youtube-crawler`/`evolver-youtube-crawler`/`trend-scout-global`/`content-selector`/`idearuncreate`)**全部**能在 T1/T2 已导入的 `system_agents` 里找到同名行(1 个 `source_kind='global_agent'`:`evolver-youtube-crawler`;5 个 `source_kind='template'`:`claude-youtube-skills`/`youtube-crawler`/`trend-scout-global`/`content-selector`/`idearuncreate`——这 5 个模板目录在 `system/templates/` 下真实存在,此前文档判断"在 global/template 里都找不到对应目录"是错的)。因此触发新建 `scope='company'` 行数 = **0**,不是预期的 4;`org_graph_nodes` 6 行全部引用已存在行。`youtube-crawler` 本身在 `system/agents/` 下也有同名目录,但该目录下没有 `agent.md`(只有 `.claude/`),T1 过滤规则将其排除,故它落在 `system_agents` 里的行是 T2 写入的 `template` 行,不是 `global_agent`。二次运行 `npm run graph:seed` 验证幂等:`org_graph_nodes` 新建 0 行、跳过 6 行,总数仍是 6。 - [x] **T4 — 行数对账 + npm 脚本接线** - `npm run graph:seed` 串联 T1→T2→T3;跑完打印按 `source_kind` 分组的行数汇总,独立于种子脚本内部计数器、重新扫描一次目录/文件做交叉核对 - 验收:连续跑两次 `npm run graph:seed` 行数不变(幂等);汇总报告三类 `source_kind` 数字都对得上 T1-T3 的真实数字 - **实际结果**:`verifyCounts()` 已加到 `server/services/graph-seed-service.js`,独立重新扫描 `system/agents/`(含 `agent.md` 过滤)、`system/templates/`(含跨源冲突规则)、`data/companies/*/company.json`(角色名去重),推导期望行数,再和 `SELECT source_kind, COUNT(*) ... GROUP BY source_kind` / `SELECT company_id, COUNT(*) FROM org_graph_nodes GROUP BY company_id` 的真实结果比对,不一致时返回 `ok:false` + `mismatches[]`。`scripts/graph-seed.js` 依次调用 `seedGlobalAgents → seedTemplates → seedCompanyAgents → verifyCounts`,打印汇总报告,`v.ok===false` 时 `process.exitCode = 1`。`package.json` 已有 `"graph:seed": "node scripts/graph-seed.js"`(此前会话已加)。连续跑两次 `npm run graph:seed`,真实数字:`global_agent=8`(`system/agents/` 现有 11 个目录,含 `agent.md` 的 8 个,文档里旧的"10"是过时数字,与本任务无关,不予改动)、`template=33`(39 个模板目录减去 6 个与 global_agent 同名被冲突保护跳过的)、`company_hired=0`(`idearun.agents[]` 6 个角色全部能对上已有行)、`org_graph_nodes[idearun]=6`。两次运行结果完全一致(幂等),第二次运行 `org_graph_nodes` 新建 0 行、跳过 6 行;直接查 SQLite 复核 `system_agents` 总行数 41(8+33)、`org_graph_nodes` 总行数 6、`org_graph_edges` 总行数 0,无重复行。另外人工注入一条无文件系统依据的假 `system_agents` 行验证 `verifyCounts()` 确实能检测出不一致(`ok:false`),且 `scripts/graph-seed.js` 在该场景下退出码为 1,验证了对账/退出码逻辑本身有效,不是摆设。 - [x] **T5 — 确认零行为变更** - 非编码任务:跑 `npm run test:unit` 全绿;`git diff --stat server/services/company-service.js` 应该没有任何改动 - 对应设计文档里 P0 的验收标准"现有 company-service.js 行为不变" - **实际结果**:`npm run test:unit` 全绿(54 test files passed, 571 tests passed, 0 failed)。`git diff --stat server/services/company-service.js server/src/core/agent-manager.js server/src/core/prompt-builder.js`(working tree 和 `--cached` 两个都跑了)输出均为空字符串,退出码 0。额外核对:这三个文件最近一次被改动的提交是 `538d5d0`,早于本次 P0/devloop 全部提交(`83523ed`/`7335930`/`e1f71cf`/`bd1636b`/`3c14a4d`),确认整个 P0 阶段这三个文件零改动(含已提交和未提交两种情况)。