Files
Cyrene_v2/internal/runtime/loop/memory_scoped_write_test.go
T
AskaEth 509dc412eb
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
feat(memory): 记忆 P2(项目索引物化 / decay 回写 / 作用域写规则 / 静默吞点 + loop 级只读红线测试)
2026-10-05 11:47:39 +08:00

66 lines
2.4 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 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)
}
}