Actor 边界总览
wesgine 的 Actor 边界覆盖四个面:Memory、Session、Observe、Cron。
两层隔离模型
Cell(Tenant) → 物理隔离(独立 DB,表内无 cell_id)
└── Actor(User) → 逻辑隔离(同一 Cell 内的请求主体)
Cell 边界落在文件路径上,不需要代码检查。 Actor 边界必须被代码收敛。
四个面
面 1:Memory(INV-MEM-38~47)
| 判据 | 执行点 |
|---|---|
| 读 | memory.ActorVisible |
| 写 | saveCore 内的 RequireActor |
| 删 | Store.DeleteAs(id, actor) |
关键:actor 是 wes_memories 表的独立列(INV-MEM-48),不再是 Metadata["actor"]。
面 2:Session(INV-SESS-01~03)
| 判据 | 执行点 |
|---|---|
| 归属 | SessionHandle.AssertActor(路由漏斗 dispatchCellSessionByID) |
| 行身份 | WHERE id = ? AND session_id = ? |
actor 是 wes_sessions 表的独立列。
面 3:Observe(INV-OBS-08~10)
| 判据 | 执行点 |
|---|---|
| SQL | actorClause(internal/observe/actor.go) |
| tool_calls | runOwnedByActor(EXISTS 子查询回父 Run) |
| 事件环 | observe.RunVisible |
空 actor 是合法值(管理视图),漏传不报错而是返回越权数据。
面 4:Cron(INV-CRON-10)
| 判据 | 执行点 |
|---|---|
| 可见性 | jobVisible(wcron.Manager) |
| by-ID | ownedJob(ctx, id, actor) |
泄漏的不是数据而是执行身份。
共同诊断陷阱
| 陷阱 | 说明 |
|---|---|
| 报障"AI 回复有别人的记忆" | 读路径通常没泄漏,真正机制是写侧越权产出无主条目 |
| 空 actor 不报错 | admin token + 空 actor = 全 Cell 视图(合法),漏传 = 无声越权 |
| 页外过滤 | 先 LIMIT 再过滤 → 同事的行占满窗口 → "我的数据不见了" |
委派子 Run 的 actor 传播
tool.go 必须把 tc.Actor 同时写进:
pp.Actor(一等字段)pp.Tags["actor"](审计)
runner.go 子 actor 为空时从 parentParams.Actor 继承。
无主行的裁决
| 面 | 无主 = ? |
|---|---|
| Memory 私有域 | 异常(缺主) |
| Memory 平台分区 | 正常(L1/L2 共享) |
| Run | 隐藏(不是"公共") |
| Cron Job | 仅 admin 可见 |
相关文档
- Memory 层模型 →
memory-layer-model.md - Session 管理 →
session-management.md - Run 生命周期 →
run-lifecycle.md