28-followups. Agent 注册表统一 —— 未完成与未确认项
所属: 28 Agent 注册表统一 的遗留清单。 主文档已随实施完成移入
docs/done/;这份留在docs/todo/,装的是还没做完和还没定的部分。 日期: 2026-08-18
为什么单独拆一份
28 号的主体(G1-G4:本体归位 system/agents/、运行态按公司/任务下沉、公司只存引用、缺则创建)
已实施并通过真 Claude CLI E2E,主文档因此移入 done/。
但整份搬走会让下面这些从待办视野里消失 —— 那种丢失是静默的, 正好是 28 号自己反复在治的那类故障。所以拆成两份:已完成的作为记录归档,未完成的留在这里。
一、未确认(方向已定、设计未定 —— 别当成拍板过的去实现)
1.1 dream 机制
状态:用户口述过要解决什么问题和大致形态,设计尚未开始。
已知的只有这些:
- 定时跑的另一套逻辑,整理所有 agent 在所有公司的 history 与 memory,显式提炼后沉淀到 skill memory
- 它是「经验汇流」的正解;错误版本是「每轮对话自动把原文写进共享
SKILL.md」—— 方向对,但直接灌原始对话等于把 A 公司的机密喂给 B 公司 (这个错误版本真的发生过,是 28 号第一轮验收挖出的最严重 blocker,已修)
尚未设计的:触发时机与频率、提炼规则、去敏策略(什么算「不含公司特定信息」)、 产物落点与格式、失败与重试、提炼质量怎么评。
已经生效的约束(这条是确定的,不随 dream 的设计变化):
公司态目录(system/agents/{aid}/{cid}/ 下的 memory/ / conversations/)是 dream 的唯一原料,
不许被任何清理策略当垃圾扫掉。详见主文档 §5.6b。
真要做时另开设计文档。不要照主文档 §5.6b 的措辞去写代码 —— 那一节的目的是锁住上面那条约束,不是给 dream 下定义。
二、已实施但未验证
来自主文档 §11.4。「已实施」不等于「已验完」,这几项目前只有单测、没有真跑证据:
| 项 | 现状 | 缺什么 |
|---|---|---|
| 新建本体路径(验收 6 前半) | 只有单测 | E2E 那轮四个角色全部命中已有本体,hireFromBaseMetaAgent → agent-creator → draft→active 这条链没有真 CLI 证据 |
| 完整 work graph 真跑(验收 9) | 未做 | E2E 停在 org 层;交付物归宿(§4.4 按链路分叉)没被大批量产物压过 |
| 边界守卫接住新建本体 | 只有注入式单测 | E2E 的 864→864 零增量只证明了运行态没漏进 git,没替「新建本体不被冤杀」作证(那一轮根本没触发新建)。见 §11.3 |
三、未实施的工程项
3.1 source_kind / legacy_path 删列(验收 2 后半)
两列仍在库里。origin 已经是真相来源,legacy_path 的所有读取点都已改成从 id 推导路径
(唯二的例外是 graph-seed-service 里判断「悬空行」时拿它做存在性检查,那是正当用法)。
删列前需确认没有遗漏的读取方。
3.2 任务态清理策略(§5.6)
只有设计,没有实现。任务目录 system/agents/{aid}/{cid}/{taskId}/ 在源码树里无限增长。
实现前必须先读主文档 §5.6b —— 公司态是 dream 的原料,不是缓存,只能清任务态。
3.3 agent-chat.js:1209 是心跳落点 bug 的第二个入口
PUT /api/agent/:agentId/heartbeat(前端 Agent 详情页走的就是它)用
locator.bodyDir(parseAddress(id).agentId) 把公司段丢掉,然后整份重写本体 config.json。
心跳落点已在 company.js 侧修好(写 system/agents/{aid}/{cid}/heartbeat.json),
但这个入口没改,且因此多了一个新问题:公司态文件一旦存在,读侧优先取公司态,
于是这个端点的写入对该 (agent, 公司) 变成静默无效。
修法(一行级):那段读改写换成
require('../services/heartbeat-service').writeHeartbeatConfig(req.params.agentId, req.body),
GET :1203 的 heartbeat: config?.heartbeat 同理换成 readHeartbeatConfig。
四、验证口径提醒
主文档 §11.3 留了一段「文档与代码一致性检查」的 shell(常量改名同步)。
路径已随文档迁移更新完毕(cd2066a),实跑三份文档全部命中当前常量名 AGENT_REGISTRY_TREE_RE。
取值域不要抄进文档。毕业闸门的权威判据只有三处:
server/services/agent-locator.js的missingBodyDefinition()server/services/graph-service.js的promoteDraftIfComplete()server/services/graph-service.js的isUngraduatedStatus()(只挡draft/training)
文档里复述取值域会产生第二份真相 —— 这个坑本仓库踩过:
一度按「≠ active 就挡」判,把库里 36 个 enabled/idle/ready/trained 的本体全判成「没填完」,
workgraph-planning / master / qa-judge 全部雇不进来。
五、已经立起来的守卫(别重复造,也别删)
这几条是沉淀下来的不变式测试(前三条出自 agent 目录重构那一轮,第四条出自 27-P3C 批 1)。它们守的都是「同一个事实只能有一处持有者」, 而且都带「样本非空」前置断言 —— 少了那一条,扫描路径一写错就会以「零违例」的形式全绿, 一条永远通过的不变式测试和没有这条测试是一回事。
| 测试 | 守什么 | 违例时 |
|---|---|---|
agents-root-single-holder.test.js |
本体根路径只能由 locator.AGENTS_ROOT 持有 |
精确点名到文件行号 |
no-stale-templates-path.test.js |
活定义里不许出现已死的 system/templates(判据:git 跟踪的才是定义,未跟踪的是运行态产物) |
同上 |
repo-hygiene.test.js |
tracked 与 ignored 不重叠 | 列出越界文件 |
runs-root-single-holder.test.js |
凡是把 process.env.GRAPH_RUNS_DIR 绑到标识符上的模块,那个标识符必须在代码里(不是注释里)真正被用到 |
精确点名到文件行号 |
第四条的来历值得记:
goal-contract.js里曾有一行const RUNS_ROOT = process.env.GRAPH_RUNS_DIR || null, 注释白纸黑字写着「与 graph-engine.RUNS_ROOT 是同一个变量(测试隔离在用)」,全文件却零引用。 一个声明了意图、代码却不兑现的常量,比没有这个常量更容易骗人 —— 读的人会据此认为该模块认这个覆盖。 它同时也是「实现在、零调用方」这个惯犯模式的又一例(本仓库有人数到第五次,有人写「十几次」)。
改动它们之前先想清楚:这三条的价值全在于「红了才有用」。 放宽判据、加例外、或者把断言改成永远成立的形式,等于把守卫拆掉 —— 本仓库有过「隔离是表演」的测试污染前科。