Files
MailUI4Agents/server/internal/handler/session_scope_hint_test.go
JianFeeeee 6e5ea42138 fix(agent): 会话作用域拒绝时说明 session_id 从哪来 —— 独立 MCP 宿主的实测卡点
## 触发它的实测

跑「独立 MCP 宿主 E2E」时,第一版客户端卡在这里:
它收到了 new_mail 事件、**知道该读那封信**,却不知道该传什么 session_id,
于是一封信都读不到,报的是「这封信不在你当前所在的那条会话里」。

## 原文案缺的那半句

原文案说「要读它,就在它那条会话里读」—— 只说了**去哪读**,
没说**怎么去读**(id 从哪来)。缺的那句正是接入端唯一缺的信息。

实测依据:new_mail 事件的 payload 有 16 个键,含
`session_id` / `session_alias` / `mail_id`;桥侧另有
`GET /api/v1/agent/session/default` 可查默认会话。

## 安全边界未动

★ 只报**调用方自己所在的会话**(`self`),绝不把目标会话 id 拼进文案 ——
  那是 2026-09-15 用户订正过的语义(原文案刻意不提目标会话,避免泄露别人的会话)。
  判据第③条专门盯这一点。

## 判据自己踩了两个坑(与「变异必须确认真的应用」同族)

1. **变异一度删掉了 490 行** —— 循环没写终止条件,从提示那行一路删到文件末尾。
   备份救回(608 行完好)。
2. **判据窗口取太宽导致假绿** —— 初版按「文案起点 + 2200 字符」截取,而
   **同一文件别处的文档注释**里也写了 `/agent/session/default`(agentScope 上方的说明)
   ⇒ 删掉提示后窗口里仍有它 ⇒ 判据绿。
   修法:按**单条 Error(...) 调用**取段,不按固定窗口。

★ 这两个坑的共同教训:**「变异应用了」≠「判据看到了正确的范围」**。
  变异一次"没生效"(我以为代码没问题)、一次"生效了但判据看错范围"(我以为判据有效)
  —— 两种都表现为 0 红。
  **「0 红」的第一反应必须是「变异或判据有一方错了」。**

14 包全绿。
2026-10-04 18:57:18 +08:00

74 lines
2.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package handler
/*
会话作用域拒绝的文案必须**指出 id 从哪来**(2026-10-04 实测驱动)。
★ 为什么要这一格:
实测「独立 MCP 宿主 E2E」时,第一版客户端卡在这里 ——
它收到了 new_mail 事件、知道该读那封信,却**不知道该传什么 session_id**,
于是一封信都读不到,报的是:
这封信不在你当前所在的那条会话里:…你当前在会话 。
原文案说了「就在它那条会话里读」(去哪读),却没说 **id 从哪来**
(怎么去读)。缺的那半句正是宿主唯一缺的信息。
★ 判据盯两件事,缺一不可:
① 提到 session_id(名字本身)
② 指出**来源**(new_mail 事件的 payload / session/default 端点)
—— 只加「请传 session_id」等于把问题原样推回去,宿主仍不知道去哪拿。
*/
import (
"os"
"strings"
"testing"
)
func TestSessionScopeHintTellsWhereToGetSessionID(t *testing.T) {
b, err := os.ReadFile("agent_discovery.go")
if err != nil {
t.Fatalf("读 agent_discovery.go: %v", err)
}
src := string(b)
i := strings.Index(src, "这封信不在你当前所在的那条会话里")
if i < 0 {
t.Fatal("找不到会话作用域的拒绝文案")
}
// ★ 只取这一条 Error(...) 调用,不能按固定窗口往后截。
// 初版用「起点 + 2200 字符」,而**同一文件别处的文档注释**里也写了
// `/agent/session/default`(那是 `agentScope` 上方的说明)⇒
// 删掉提示后窗口里仍有它 ⇒ 判据假绿。
// 这与「变异必须确认真的应用」同族,但更隐蔽:变异应用了、判据却因为
// **看错了范围**而没反应。
seg := src[i:]
if end := strings.Index(seg, `Error(w, http.StatusForbidden, "无权访问该会话"`); end > 0 {
seg = seg[:end]
}
// ① 提到 session_id
if !strings.Contains(seg, "session_id") {
t.Error("★ 拒绝文案里没有 session_id —— 调用方不知道该传什么")
}
// ② 指出来源:事件载荷 或 默认会话语义端点
hasEvent := strings.Contains(seg, "new_mail")
hasEndpoint := strings.Contains(seg, "/agent/session/default")
if !hasEvent && !hasEndpoint {
t.Error("★ 只说了「要传 session_id」却没说**从哪拿** ——" +
" 那等于把问题原样推回去,宿主仍然读不到信(实测卡点)")
}
// ③ 不得泄露目标会话 id(安全边界:那是别人的会话)
if strings.Contains(seg, `self = (*scope).String()`) &&
strings.Contains(seg, "self+"+"\" 目标会话") {
t.Error("★ 不得把目标会话 id 拼进文案 —— 那是安全边界(只报自己所在的会话)")
}
}
func min2(a, b int) int {
if a < b {
return a
}
return b
}