fix(read)!: 会话即主体 —— 读路径不再做任何"谁有资格"的仲裁
用户(第二次、说明白了):「我要求的是不同 session 不同收件箱,而不是复杂的权限隔离……
每个 session 是相对独立的单位,他们不应该公用一个相对私有化的设施,相当于每个 session
概念上是一个独立的『用户』」
所以 AgentMayReadSession 只剩一句话:**target 必须就是 scope**(我当前所在的那条会话)。
删掉两样东西:
· 工作区比较 —— 那是 cwd/沙箱那条轴的事,混进读信就制造了 zcode 那次误判
(cross-workspace 的 403 让它推断"那五位 agent 不存在");
· **参与性仲裁** —— 那是我加的"相对私有化"设施:把 agent 当成一个跨所有会话的人,
于是它既太松(同工作区内能互翻收件箱)又太严(发起者读不到自己发起的会话)。
会话是独立单位,不需要一个更高层身份来"授权"它读自己的收件箱。
信任边界在桥:session_id 由 worker 闭包注入(模型改不了),等同"邮件客户端替它持有的
每个账号行事"。未声明 scope 的旧语义保持放行(记警告)。
判据重写为:① 我就是这条会话 → 放行;② 同工作区另一条会话 → 拒;③ 别的工作区会话 → 拒
(同一个理由 not-your-session);④ 未声明 → 迁移期放行;⑤ **显式钉住"不做参与性仲裁"**
(声明自己是哪条会话即以其行事,即便该 agent 名义上没参与过)—— 这条是模型的一部分,
免得以后被"好心"加回来;将来若要做"每个 session 自带凭据",那是加凭据而不是加回这层仲裁。
生产实测:① 200;② 403「这封信不在你当前所在的那条会话里……」;③ 200(迁移期放行)。
This commit is contained in:
@ -36,45 +36,33 @@ func SessionWorkspaceOf(ctx context.Context, id uuid.UUID) string {
|
||||
|
||||
// AgentMayReadSession 判「以 `scope` 为当前会话的 Agent 能不能读 `target`」。
|
||||
//
|
||||
// ★ 2026-09-15 用户订正(原话:「是应该发到对应 session 的信,因为 agent 多 session
|
||||
// 架构,不同 session 的记忆是隔离的。你之前那个修法简直荒谬」):
|
||||
// ★ 2026-09-15 用户把模型说明白了(两次,第二次我看懂了):
|
||||
//
|
||||
// **读信这条路只认会话,不认工作区。**
|
||||
// 「我要求的是不同 session 不同收件箱,而不是复杂的权限隔离……每个 session 是相对
|
||||
// 独立的单位,他们不应该公用一个相对私有化的设施,相当于每个 session 概念上是一个
|
||||
// 独立的『用户』」
|
||||
//
|
||||
// ① target 必须就是 `scope`(我当前所在的那条会话)—— 「不同 session 不同收件箱」
|
||||
// ② 我确实参与过 target(防伪造 session_id:声明别人的会话也不行)
|
||||
// 那么这里就不该有任何"谁有资格读谁"的仲裁 —— **会话本身就是那个私有的单位**:
|
||||
//
|
||||
// # 为什么删掉原先的「工作区相同」那道闸门
|
||||
// target 必须就是 `scope`(我当前所在的那条会话)。
|
||||
//
|
||||
// 我把两条轴混在了一起:**工作区决定 cwd / 沙箱 / 谁能看到哪些线索**,
|
||||
// 而**会话决定记忆与收件箱** —— 一个 agent 同时服务多个工作区,正是"多会话"
|
||||
// 架构存在的理由。于是原先那条判据两头都错:
|
||||
// 别的东西一概不看:不看工作区(那是 cwd/沙箱那条轴的事),也不看"这个 agent 参没参与过"
|
||||
// (那是我之前加的"相对私有化"设施 —— 它把 agent 当成一个跨越所有会话的人,
|
||||
// 既制造了越界读(同工作区里能读别的会话),又挡住了正当读者(发起者读不到自己发起的
|
||||
// 会话,zcode 因此推断出"那五位 agent 不存在")。会话是独立单位,它不需要被一个
|
||||
// 更高层的身份来"授权"。
|
||||
//
|
||||
// · 太松:同一个工作区里,我参与过的**别的会话**也放行了 —— 而会话之间记忆隔离,
|
||||
// 读别的会话等于绕过隔离(用户的原始要求就是"不同 session 不同收件箱");
|
||||
// · 太严:我在 A 工作区的上下文里,读不到**自己刚发起**的、B 工作区那条会话 ——
|
||||
// 发起者读不到自己的会话(zcode 2026-09-15 撞上这条,403 之后它推断出
|
||||
// "那五位 agent 不存在",把错误结论写进了给人的信里)。
|
||||
//
|
||||
// 会话边界一处定死之后,两侧都对了:worker 在哪条会话里,就只看得见那条的收件箱;
|
||||
// 要读另一条,就得在那条会话里(每封来信都会把 worker 唤醒到它自己那条会话上)。
|
||||
// 信任边界在**桥**:`session_id` 由 worker 闭包注入(模型改不了),桥是我们的可信组件。
|
||||
// 这与「一个邮件客户端替它持有的每个账号收发信」是同一种信任:声明自己是哪条会话,
|
||||
// 就以那条会话的身份行事。首次接线前的旧语义(未声明 scope)保持放行并记警告日志。
|
||||
func AgentMayReadSession(ctx context.Context, agentName string, scope *uuid.UUID, target uuid.UUID) (bool, string, error) {
|
||||
// 未声明当前会话:无法判断"你人在哪条会话里",按迁移期旧语义放行(服务端另记警告)。
|
||||
// 五家桥实测都会带 session_id(agent_discovery 的 agentScope)。
|
||||
_ = ctx
|
||||
_ = agentName
|
||||
if scope == nil {
|
||||
return true, "", nil
|
||||
return true, "", nil // 迁移期:未声明当前会话者按旧语义放行(服务端另记警告)
|
||||
}
|
||||
// ① 只读自己当前那条会话 —— 不同 session 就是不同收件箱
|
||||
if *scope != target {
|
||||
return false, "not-your-session", nil
|
||||
}
|
||||
// ② 防伪造 session_id:声明一条自己没参与的会话也不行
|
||||
participates, err := AgentCanAccessSession(ctx, agentName, target)
|
||||
if err != nil {
|
||||
return false, "", err
|
||||
}
|
||||
if !participates {
|
||||
return false, "not-participant", nil
|
||||
}
|
||||
return true, "", nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user