66 lines
2.4 KiB
Go
66 lines
2.4 KiB
Go
package loop
|
||
|
||
import (
|
||
"context"
|
||
"testing"
|
||
|
||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/memory"
|
||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/model"
|
||
)
|
||
|
||
// fixedExtractor(定义见 flow_spans_test.go)返回一组固定条目,用于驱动持久化
|
||
// 路径的边界断言。
|
||
|
||
// TestPersistMemories_ScopedWriteRule_RejectsForeignPersona 钉住审计 2026-10-05
|
||
// §1.3「Store 作用域写规则未接线」:提取持久化经 Store 的作用域写规则
|
||
// (AddScoped)落库。一条归属**别的角色**的角色作用域条目必须被拒(ErrReadOnly),
|
||
// 绝不被冒充成本回合角色的日常记忆。
|
||
func TestPersistMemories_ScopedWriteRule_RejectsForeignPersona(t *testing.T) {
|
||
t.Parallel()
|
||
store := newTestMemoryStore(t)
|
||
l := New(Options{
|
||
Memory: store,
|
||
Extractor: fixedExtractor{items: []memory.MemoryItem{
|
||
{PersonaID: "persona-b", Scope: memory.ScopePersona, Kind: memory.KindRelationship, Content: "b 的角色日常"},
|
||
}},
|
||
PersonaID: "persona-a",
|
||
})
|
||
|
||
ctx := WithSessionEnv(context.Background(), OwnerEnv())
|
||
l.extractMemory(ctx, []model.Message{model.TextMessage(model.RoleUser, "记住 b 的日常")}, 1)
|
||
|
||
items, err := store.List(context.Background())
|
||
if err != nil {
|
||
t.Fatalf("List: %v", err)
|
||
}
|
||
if len(items) != 0 {
|
||
t.Fatalf("跨角色的角色作用域写被接受:%d 条(作用域写规则未接线)", len(items))
|
||
}
|
||
}
|
||
|
||
// TestPersistMemories_PersonaAgnosticExtractor_StampedByStore 证明接线后正常路径
|
||
// 不变:与角色无关的提取器(PersonaID 为空)产出的条目仍由 Store 用本回合角色
|
||
// (actorID)补齐归属,照常落库。
|
||
func TestPersistMemories_PersonaAgnosticExtractor_StampedByStore(t *testing.T) {
|
||
t.Parallel()
|
||
store := newTestMemoryStore(t)
|
||
l := New(Options{
|
||
Memory: store,
|
||
Extractor: fixedExtractor{items: []memory.MemoryItem{
|
||
{Scope: memory.ScopePersona, Kind: memory.KindRelationship, Content: "主人爱喝冰美式"},
|
||
}},
|
||
PersonaID: "persona-a",
|
||
})
|
||
|
||
ctx := WithSessionEnv(context.Background(), OwnerEnv())
|
||
l.extractMemory(ctx, []model.Message{model.TextMessage(model.RoleUser, "记住 我爱喝冰美式")}, 1)
|
||
|
||
items, err := store.ListByPersona(context.Background(), "persona-a")
|
||
if err != nil {
|
||
t.Fatalf("ListByPersona: %v", err)
|
||
}
|
||
if len(items) != 1 || items[0].PersonaID != "persona-a" {
|
||
t.Fatalf("角色无关提取器未被 Store 盖章:%+v", items)
|
||
}
|
||
}
|