107 lines
3.9 KiB
Go
107 lines
3.9 KiB
Go
package graph
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/local/glpi-neural-brain/internal/model"
|
|
)
|
|
|
|
func TestReplaceOriginsPreservesUnchangedVector(t *testing.T) {
|
|
s, err := Open(t.TempDir())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() { _ = s.Close() })
|
|
n := model.Node{ID: "n1", Kind: "knowledge", Label: "VPN", Summary: "Gateway", Origin: "knowledge-production"}
|
|
s.ReplaceOrigins([]string{"knowledge-production"}, []model.Node{n}, nil)
|
|
s.SetVector("n1", []float64{1, 2, 3})
|
|
s.ReplaceOrigins([]string{"knowledge-production"}, []model.Node{n}, nil)
|
|
v, ok := s.Vector("n1")
|
|
if !ok || len(v) != 3 {
|
|
t.Fatalf("vector was not preserved: %v %v", ok, v)
|
|
}
|
|
n.Summary = "changed"
|
|
s.ReplaceOrigins([]string{"knowledge-production"}, []model.Node{n}, nil)
|
|
if _, ok := s.Vector("n1"); ok {
|
|
t.Fatal("changed document retained stale vector")
|
|
}
|
|
}
|
|
|
|
func TestRejectedEdgePreventsPairReprocessingButIsHidden(t *testing.T) {
|
|
s, _ := Open(t.TempDir())
|
|
t.Cleanup(func() { _ = s.Close() })
|
|
a := model.Node{ID: "a", Kind: "knowledge", Label: "A", Origin: "knowledge-production"}
|
|
b := model.Node{ID: "b", Kind: "knowledge", Label: "B", Origin: "knowledge-production"}
|
|
s.UpsertNode(a)
|
|
s.UpsertNode(b)
|
|
s.SetVector("a", []float64{1, 0})
|
|
s.SetVector("b", []float64{.9, .1})
|
|
if _, _, _, ok := s.BestPair(.5); !ok {
|
|
t.Fatal("expected candidate pair")
|
|
}
|
|
s.UpsertEdge(model.Edge{Source: "a", Target: "b", Type: "related_to", Origin: "ai-inference", Status: "rejected"})
|
|
if _, _, _, ok := s.BestPair(.5); ok {
|
|
t.Fatal("rejected pair was selected again")
|
|
}
|
|
if got := len(s.Snapshot().Edges); got != 0 {
|
|
t.Fatalf("rejected edge should not be rendered, got %d", got)
|
|
}
|
|
}
|
|
|
|
func TestNextPairUsesBoundedRotatingAnchors(t *testing.T) {
|
|
s, _ := Open(t.TempDir())
|
|
t.Cleanup(func() { _ = s.Close() })
|
|
for _, id := range []string{"a", "b", "c", "d"} {
|
|
s.UpsertNode(model.Node{ID: id, Kind: "knowledge", Label: id, Origin: "knowledge-production"})
|
|
}
|
|
s.SetVector("a", []float64{1, 0})
|
|
s.SetVector("b", []float64{.99, .01})
|
|
s.SetVector("c", []float64{0, 1})
|
|
s.SetVector("d", []float64{.01, .99})
|
|
|
|
a, b, _, ok, comparisons := s.NextPair(.8, 1)
|
|
if !ok || comparisons == 0 {
|
|
t.Fatalf("expected bounded candidate search, ok=%v comparisons=%d", ok, comparisons)
|
|
}
|
|
s.UpsertEdge(model.Edge{Source: a.ID, Target: b.ID, Type: "related_to", Origin: "ai-inference", Status: "rejected"})
|
|
_, _, _, _, comparisons = s.NextPair(.8, 1)
|
|
if comparisons == 0 {
|
|
t.Fatal("rotating anchor did not advance after rejected pair")
|
|
}
|
|
if _, _, _, ok, comparisons = s.NextPair(.8, 1); !ok || comparisons == 0 {
|
|
t.Fatalf("rotating anchor did not reach the next semantic region, ok=%v comparisons=%d", ok, comparisons)
|
|
}
|
|
}
|
|
|
|
func TestCategoryFiltersLimitEmbeddingAndThinkingCandidates(t *testing.T) {
|
|
s, err := Open(t.TempDir())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() { _ = s.Close() })
|
|
nodes := []model.Node{
|
|
{ID: "net-a", Kind: "knowledge", Label: "Net A", Categories: []string{"Netzwerk"}, Origin: "test"},
|
|
{ID: "net-b", Kind: "knowledge", Label: "Net B", Categories: []string{"Netzwerk"}, Origin: "test"},
|
|
{ID: "app-a", Kind: "knowledge", Label: "App A", Categories: []string{"Applikation"}, Origin: "test"},
|
|
{ID: "none", Kind: "knowledge", Label: "Ohne", Origin: "test"},
|
|
}
|
|
for _, node := range nodes {
|
|
s.UpsertNode(node)
|
|
}
|
|
pending := s.NodesForEmbeddingFiltered([]string{"Netzwerk"})
|
|
if len(pending) != 2 {
|
|
t.Fatalf("expected two network embeddings, got %d", len(pending))
|
|
}
|
|
uncategorized := s.NodesForEmbeddingFiltered([]string{"__uncategorized__"})
|
|
if len(uncategorized) != 1 || uncategorized[0].ID != "none" {
|
|
t.Fatalf("unexpected uncategorized nodes: %#v", uncategorized)
|
|
}
|
|
for _, node := range nodes {
|
|
s.SetVector(node.ID, []float64{1, .01})
|
|
}
|
|
a, b, _, ok, _ := s.NextPairFiltered(.5, 8, []string{"Netzwerk"})
|
|
if !ok || a.Categories[0] != "Netzwerk" || b.Categories[0] != "Netzwerk" {
|
|
t.Fatalf("thinking filter returned wrong pair: ok=%v a=%+v b=%+v", ok, a, b)
|
|
}
|
|
}
|