Files
weichen 92ede3b970
ci / vet-and-test (pull_request) Successful in 37s
Close the EXT-8 remaining blocks: vector sharing, hostapi face, citation consistency
Why: EXT-8 closure needs the vector channel shared (not just fulltext), the /host/v1 knowledge face honoring the authorizer, and citation-ref-to-artifact consistency pinned as an acceptance test.
Evidence: TestRetrieveSharedVectorChannel (hash embedder: authorized shared vector hit retrievable, denied yields zero), TestSharedSearchFace (hostapi switches to SharedSearch when wired), TestSharedCitationRefDownloadable (shared hit -> Ref -> artifact content download for the authorized member); go test ./... 32/32 packages ok.
Impact: store.SearchKnowledgeVectorsShared; rag.Pipeline.RetrieveShared (own + shared fulltext + shared vector, RRF-merged); server searchKnowledge prefers RetrieveShared when the retriever implements it; hostapi Server.SharedSearch wired in the composition root through the same authorizer slot. Default behavior unchanged.
Refs: EXT-8 proposal acceptance; slices 1-2.
2026-10-08 17:16:10 +00:00

54 lines
2.0 KiB
Go

package rag
import (
"context"
"path/filepath"
"testing"
"agent-system-backend/internal/settings"
"agent-system-backend/internal/store"
core "agent-system-core"
)
// EXT-8 余项红/绿:向量通道共享——他人 owner 的向量命中经 allow 放行可检。
// 用 hash 档 embedder(确定性向量),owner=alice 建项目知识并嵌入;bob 经
// RetrieveShared 放行后命中(含 vector Kind),拒绝时零命中。
func TestRetrieveSharedVectorChannel(t *testing.T) {
st, err := store.OpenSQLite(filepath.Join(t.TempDir(), "t.db"))
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { st.Close() })
set := settings.NewService(st)
p := NewPipeline(st, set, nil, nil)
p.SetEmbedder(SwitchingEmbedder{Provider: func() string { return "hash" }})
docs := []core.KnowledgeDoc{{Owner: "alice", ProjectID: "prj-s", Source: "plugin:rdm",
Ref: "kb-v", Chunk: "向量共享独占词"}}
// 只走管线写入(分块行+向量一体;不再手工 AddKnowledge 避免主键冲突)。
if err := indexForTest(t, st, p, docs); err != nil {
t.Fatal(err)
}
allow := func(docOwner, projectID core.ID) bool {
return docOwner == "alice" && projectID == "prj-s"
}
hits, err := p.RetrieveShared(context.Background(), "bob", core.RetrievalQuery{Text: "向量共享独占词", TopK: 5}, allow)
if err != nil {
t.Fatal(err)
}
if len(hits) == 0 {
t.Fatal("authorized shared vector hit must be retrievable(向量通道共享)")
}
deny := func(docOwner, projectID core.ID) bool { return false }
if hits2, _ := p.RetrieveShared(context.Background(), "bob", core.RetrievalQuery{Text: "向量共享独占词", TopK: 5}, deny); len(hits2) != 0 {
t.Fatalf("denied shared search = %d hits, want 0", len(hits2))
}
}
// indexForTest:把 docs 直接嵌入并落向量(复用管线的公开写入路径)。
func indexForTest(t *testing.T, st *store.Store, p *Pipeline, docs []core.KnowledgeDoc) error {
t.Helper()
return p.IndexChunks(context.Background(), "alice", docs)
}