Cell 身份连续性
wesgine 的 Cell 注册表(Cell Registry)维护 Cell ID 到实例的映射,并通过一组不变量保证 Cell 身份在进程生命周期内的连续性。
核心不变量
INV-CELL-06:身份连续性
registry 有 ID ⇔ 内存必有骨架(Stopped 除外)。
Get未命中必须 hydrate;restore/Create 失败不得把仍注册的目录当孤儿改名。
含义:
- 注册表说"这个 Cell 存在",内存里就必须有对应的骨架对象
Get(cellID)在内存没找到时,必须从磁盘水化(hydrate)一个骨架- 不能因为某次操作失败,就把一个仍在注册表中的 Cell 目录改名归档
INV-CELL-07:孤儿目录改名时机
孤儿目录改名仅在
registry.Create成功之后。
含义:
- 发现磁盘上有一个 Cell 目录但注册表中没有对应 ID → 这是"孤儿目录"
- 只有在新建 Cell 成功注册后,才允许把孤儿目录改名归档
- 如果 Create 失败了,不能碰那个目录——它可能属于一个还在注册表中的 Cell
INV-CELL-08:Cell 启动条件
Cell.Start/WarmUp的合法输入 = 身份 + 已 Bind 的进程 hook。live-token 且ProviderLiveKeyFn==nil时 fail-loud。
含义:
- Cell 启动需要两样东西:身份(ID 已注册)和进程级 hook(HostEnvironment、ProviderLiveKeyFn 等)
- 如果 Cell 配置了
wes:/org:provider(需要 live token),但没有绑定ProviderLiveKeyFn,引擎直接报错 hyp.Start()永不Cell.Start()——它只挂身份骨架
水化(Hydrate)流程
Get(cellID)
→ 内存查找
→ 命中 → 返回
→ 未命中 → 查注册表
→ 注册表有 → 从磁盘 hydrate 骨架(Cool 态)→ 返回
→ 注册表没有 → 返回 ErrCellNotFound
水化出的 Cell 是 Cool 态(无 goroutine、无 DB 连接),首次请求到达时自动 WarmUp。
事故案例
2026-09 teleclaw 事故:旧版二进制读新格式 spec → decode 失败 → Get 返回 404 → 自动创建触发 → 旧目录被当孤儿归档 → 部门会话/记忆/知识库消失。
修复后:
Get对不可解码的 spec 返回ErrSpecUndecodable(非 404)GetOrCreate不再 fall through 到Create- 孤儿改名只在
Create成功后
相关 API
| 操作 | 行为 |
|---|---|
Cells().Create(spec) | 注册 + 初始化目录 + 持久化 spec |
Cells().Get(cellID) | 内存查找 → 必要时 hydrate |
Cells().GetOrCreate(spec) | Get → 命中则 merge spec → 未命中则 Create |
Cells().Delete(cellID) | registry 行 + 磁盘字节,二者都删 |
相关文档
- Cell 注册表 →
cell-registry.md - Cell Boot 序列 →
cell-boot-sequence.md - Cell 停止与删除 →
cell-stop-delete.md - Cell 温度管理 →
temperature.md