package domain_test import ( "git.cin.su/m/Assistant/contracts/interaction" "git.cin.su/m/Assistant/modules/interaction/domain" "strings" "testing" ) func TestGen2ContextUsesRetrievalProjectionAndKeepsV1Fallback(t *testing.T) { got := domain.BuildGen2Context([]interaction.HumanUtterance{{ID: "u", Content: "Я сейчас в Москве", ReceivedAtUnixMillis: 1}}) if got.Source != "retrieval:interaction-utterances" || got.UsedPersonalMemoryFallback { t.Fatalf("got %#v", got) } empty := domain.BuildGen2Context(nil) if !empty.UsedPersonalMemoryFallback { t.Fatalf("fallback missing: %#v", empty) } } func TestGen2ContextDoesNotProjectAnotherPrincipal(t *testing.T) { got := domain.BuildScopedGen2Context([]interaction.HumanUtterance{ {ID: "mine", PrincipalID: "principal-1", Content: "Я сейчас в Москве", ReceivedAtUnixMillis: 2}, {ID: "other", PrincipalID: "principal-2", Content: "Я сейчас в Казани", ReceivedAtUnixMillis: 3}, }, "principal-1") if got.Text == "" || strings.Contains(got.Text, "Казани") || !strings.Contains(got.Text, "Москве") { t.Fatalf("scoped context=%#v", got) } } func TestGen2ContextProjectsExplicitRememberedAssertion(t *testing.T) { got := domain.BuildScopedGen2Context([]interaction.HumanUtterance{ {ID: "assertion", PrincipalID: "principal-1", Content: "Для этого разговора запомни: мой тестовый цвет — синий.", ReceivedAtUnixMillis: 1}, }, "principal-1") if got.Source != "retrieval:interaction-assertions" || got.UsedPersonalMemoryFallback || !strings.Contains(got.Text, "тестовый цвет = синий") { t.Fatalf("remembered assertion was not projected: %#v", got) } } func TestGen2ContextSelectsArbitraryRelevantCurrentAssertion(t *testing.T) { history := []interaction.HumanUtterance{ {ID: "assertion", PrincipalID: "principal-1", Content: "контрольный код = ORBIT-731", ReceivedAtUnixMillis: 1}, {ID: "turn-1", PrincipalID: "principal-1", Content: "Спасибо", ReceivedAtUnixMillis: 2}, {ID: "turn-2", PrincipalID: "principal-1", Content: "Продолжим", ReceivedAtUnixMillis: 3}, } got := domain.BuildScopedGen2ContextForQuery(history, nil, "principal-1", "", "Какой контрольный код я назвал?") if got.Source != "retrieval:interaction-assertions" || !strings.Contains(got.Text, "ORBIT-731") || len(got.Fragments) != 1 { t.Fatalf("arbitrary assertion was not selected: %#v", got) } } func TestGen2ContextKeepsHistoricalAssertionOutOfCurrentProjection(t *testing.T) { history := []interaction.HumanUtterance{ {ID: "old", PrincipalID: "principal-1", Content: "контрольный код = OLD-111", ReceivedAtUnixMillis: 1}, {ID: "new", PrincipalID: "principal-1", Content: "контрольный код = NEW-222", ReceivedAtUnixMillis: 2}, } got := domain.BuildScopedGen2ContextForQuery(history, nil, "principal-1", "", "Какой контрольный код?") if strings.Contains(got.Text, "OLD-111") || !strings.Contains(got.Text, "NEW-222") || len(got.Historical) != 1 || !strings.Contains(got.Historical[0].Text, "OLD-111") { t.Fatalf("current/historical assertion separation failed: %#v", got) } } func TestGen2ContextCorrectionSupersedesBeforeTimestampTieBreaker(t *testing.T) { history := []interaction.HumanUtterance{ {ID: "observed-later", PrincipalID: "principal-1", Content: "контрольный код = LATER", ReceivedAtUnixMillis: 9}, {ID: "original", PrincipalID: "principal-1", Content: "контрольный код = ORIGINAL", ReceivedAtUnixMillis: 1}, {ID: "correction", PrincipalID: "principal-1", Content: "контрольный код = CORRECTED", ReceivedAtUnixMillis: 2, CorrectsUtteranceID: "observed-later"}, } got := domain.BuildScopedGen2ContextForQuery(history, nil, "principal-1", "", "Какой контрольный код?") if !strings.Contains(got.Text, "CORRECTED") || strings.Contains(got.Text, "LATER") { t.Fatalf("explicit correction did not supersede: %#v", got) } } func TestGen2ContextHardFiltersProjectReferencesBeforeRanking(t *testing.T) { history := []interaction.HumanUtterance{ {ID: "a", PrincipalID: "principal-1", Content: "контрольный код = ALPHA", ReceivedAtUnixMillis: 1}, {ID: "b", PrincipalID: "principal-1", Content: "контрольный код = BETA", ReceivedAtUnixMillis: 2}, } references := []interaction.ProjectReference{ {ID: "ref-a", UtteranceID: "a", ProjectID: "company-a"}, {ID: "ref-b", UtteranceID: "b", ProjectID: "company-b"}, } for projectID, expected := range map[string]struct{ want, absent string }{ "company-a": {want: "ALPHA", absent: "BETA"}, "company-b": {want: "BETA", absent: "ALPHA"}, } { got := domain.BuildScopedGen2ContextForQuery(history, references, "principal-1", projectID, "Какой контрольный код?") if !strings.Contains(got.Text, expected.want) || strings.Contains(got.Text, expected.absent) || len(got.Fragments) != 1 || got.Fragments[0].ScopeRef != projectID { t.Fatalf("scope %s leaked context: %#v", projectID, got) } } } func TestGen2ContextExcludesIrrelevantAssertionsFromBoundedProjection(t *testing.T) { history := []interaction.HumanUtterance{ {ID: "code", PrincipalID: "principal-1", Content: "контрольный код = ORBIT-731", ReceivedAtUnixMillis: 1}, {ID: "city", PrincipalID: "principal-1", Content: "город встречи = Казань", ReceivedAtUnixMillis: 2}, } got := domain.BuildScopedGen2ContextForQuery(history, nil, "principal-1", "", "Какой контрольный код?") if strings.Contains(got.Text, "Казань") || len(got.Fragments) != 1 { t.Fatalf("irrelevant assertion entered bounded projection: %#v", got) } }