Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0acbe53fad | ||
|
|
e634bb946a | ||
|
|
c7ad996cae | ||
|
|
a065382512 |
@@ -0,0 +1,90 @@
|
||||
package epistemics
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.cin.su/m/Assistant/contracts/world"
|
||||
)
|
||||
|
||||
type VolatilityMode string
|
||||
|
||||
const (
|
||||
VolatilityImmutable VolatilityMode = "IMMUTABLE"
|
||||
VolatilityVersionBound VolatilityMode = "VERSION_BOUND"
|
||||
VolatilityVerySlow VolatilityMode = "VERY_SLOW"
|
||||
VolatilitySlow VolatilityMode = "SLOW"
|
||||
VolatilityMedium VolatilityMode = "MEDIUM"
|
||||
VolatilityFast VolatilityMode = "FAST"
|
||||
VolatilityEphemeral VolatilityMode = "EPHEMERAL"
|
||||
VolatilityCustom VolatilityMode = "CUSTOM"
|
||||
)
|
||||
|
||||
type TemporalApplicability struct {
|
||||
ObservedAtUnixMillis int64
|
||||
ValidFromUnixMillis *int64
|
||||
ValidUntilUnixMillis *int64
|
||||
LastVerifiedAtUnixMillis *int64
|
||||
Volatility VolatilitySpec
|
||||
VersionBindings []world.VersionBinding
|
||||
}
|
||||
type VolatilitySpec struct {
|
||||
Mode VolatilityMode
|
||||
ExpectedChangeIntervalMillis *int64
|
||||
RevalidateAfterMillis *int64
|
||||
HardStaleAfterMillis *int64
|
||||
InvalidateOnVersionChange bool
|
||||
RevalidationPolicyRef string
|
||||
}
|
||||
type FreshnessAssessmentState string
|
||||
|
||||
const (
|
||||
FreshnessAssessmentCurrent FreshnessAssessmentState = "CURRENT"
|
||||
FreshnessAssessmentAcceptable FreshnessAssessmentState = "ACCEPTABLE"
|
||||
FreshnessAssessmentAging FreshnessAssessmentState = "AGING"
|
||||
FreshnessAssessmentStale FreshnessAssessmentState = "STALE"
|
||||
FreshnessAssessmentVersionMismatch FreshnessAssessmentState = "VERSION_MISMATCH"
|
||||
FreshnessAssessmentHistoricalOnly FreshnessAssessmentState = "HISTORICAL_ONLY"
|
||||
FreshnessAssessmentUnknown FreshnessAssessmentState = "UNKNOWN"
|
||||
)
|
||||
|
||||
type FreshnessAssessment struct {
|
||||
SourceKnowledgeRef string
|
||||
TaskRef string
|
||||
State FreshnessAssessmentState
|
||||
Reason string
|
||||
AgeMillis int64
|
||||
VersionMatchState string
|
||||
RevalidationAttemptRef string
|
||||
AssessedAtUnixMillis int64
|
||||
}
|
||||
type RevalidationRequest struct {
|
||||
ID string
|
||||
SourceKnowledgeRef string
|
||||
TaskRef string
|
||||
RequiredVersionRefs []world.SemanticReference
|
||||
RequestedAtUnixMillis int64
|
||||
}
|
||||
type RevalidationResponse struct {
|
||||
RequestID string
|
||||
Assessment FreshnessAssessment
|
||||
NewEvidenceRefs []EvidenceRef
|
||||
CompletedAtUnixMillis int64
|
||||
}
|
||||
|
||||
func (v VolatilitySpec) Validate() error {
|
||||
if v.Mode == "" {
|
||||
return fmt.Errorf("volatility mode is required")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (t TemporalApplicability) Validate() error {
|
||||
if t.ObservedAtUnixMillis < 1 {
|
||||
return fmt.Errorf("observed time is required")
|
||||
}
|
||||
return t.Volatility.Validate()
|
||||
}
|
||||
func (a FreshnessAssessment) Validate() error {
|
||||
if a.SourceKnowledgeRef == "" || a.TaskRef == "" || a.State == "" || a.AgeMillis < 0 || a.AssessedAtUnixMillis < 1 {
|
||||
return fmt.Errorf("freshness assessment is incomplete")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package epistemics
|
||||
|
||||
import "git.cin.su/m/Assistant/platform/ids"
|
||||
|
||||
type BeliefState string
|
||||
|
||||
const (
|
||||
@@ -9,19 +11,27 @@ const (
|
||||
)
|
||||
|
||||
type Observation struct {
|
||||
ID ObservationID
|
||||
SourceSnapshot SourceSnapshotID
|
||||
Excerpt SourceExcerptID
|
||||
Text string
|
||||
ObservedAt int64
|
||||
ID ObservationID
|
||||
SourceSnapshot SourceSnapshotID
|
||||
Excerpt SourceExcerptID
|
||||
Text string
|
||||
ObservedAt int64
|
||||
PrincipalID string
|
||||
ContextScopeRef string
|
||||
ObservationKind string
|
||||
Payload string
|
||||
ExtractorRef string
|
||||
}
|
||||
|
||||
type Claim struct {
|
||||
ID ClaimID
|
||||
Statement string
|
||||
ObservationID ObservationID
|
||||
CitationID CitationID
|
||||
Verification VerificationState
|
||||
ID ClaimID
|
||||
Statement string
|
||||
ObservationID ObservationID
|
||||
CitationID CitationID
|
||||
Verification VerificationState
|
||||
PropositionID ids.ID
|
||||
RevisedFrom *ClaimID
|
||||
RecordedAtUnixMillis int64
|
||||
}
|
||||
|
||||
type Belief struct {
|
||||
|
||||
@@ -24,6 +24,8 @@ type HelpMethodKind string
|
||||
type OutcomeClass string
|
||||
type ReflectionTriggerKind string
|
||||
type ReflectionCandidateState string
|
||||
type PropositionKind string
|
||||
type BeliefAssessmentState string
|
||||
|
||||
const (
|
||||
VerificationUnverified VerificationState = "UNVERIFIED"
|
||||
@@ -73,6 +75,12 @@ const (
|
||||
ReflectionCandidateEvaluating ReflectionCandidateState = "EVALUATING"
|
||||
ReflectionCandidateSuperseded ReflectionCandidateState = "SUPERSEDED"
|
||||
ReflectionCandidateResolved ReflectionCandidateState = "RESOLVED"
|
||||
PropositionWorldFacet PropositionKind = "WORLD_FACET"
|
||||
PropositionWorldRelation PropositionKind = "WORLD_RELATION"
|
||||
PropositionOwnerDefined PropositionKind = "OWNER_DEFINED"
|
||||
PropositionTextual PropositionKind = "TEXTUAL"
|
||||
BeliefAssessmentCurrent BeliefAssessmentState = "CURRENT"
|
||||
BeliefAssessmentSuperseded BeliefAssessmentState = "SUPERSEDED"
|
||||
)
|
||||
|
||||
// SystemExpectation records what Domovoy expected a meaningful help path to
|
||||
@@ -114,6 +122,15 @@ type ExperienceRecord struct {
|
||||
VerificationEvidence []EvidenceRef
|
||||
ConfidenceMillis int64
|
||||
RecordedAtUnixMillis int64
|
||||
ProblemStatement string
|
||||
AttemptRef string
|
||||
WhyAttempted string
|
||||
ApplicabilityConditions []string
|
||||
ContextScopeRef string
|
||||
EpisodeRef string
|
||||
GoalRef string
|
||||
TaskRef string
|
||||
WhySucceededOrFailed string
|
||||
}
|
||||
|
||||
// ReflectionCandidate records that broader reflection may be warranted.
|
||||
@@ -134,3 +151,34 @@ type ReflectionCandidate struct {
|
||||
ClaimedBy string
|
||||
ClaimExpiresAtUnixMillis int64
|
||||
}
|
||||
|
||||
type Proposition struct {
|
||||
ID ids.ID
|
||||
Kind PropositionKind
|
||||
SubjectRef string
|
||||
PredicateRef string
|
||||
ObjectValue string
|
||||
ObjectRef string
|
||||
Qualifiers []string
|
||||
TextFallback string
|
||||
}
|
||||
|
||||
type BeliefAssessment struct {
|
||||
ID ids.ID
|
||||
ClaimID ClaimID
|
||||
Revision ids.Revision
|
||||
State BeliefAssessmentState
|
||||
ConfidenceMillis int64
|
||||
EvidenceRefs []EvidenceRef
|
||||
AssessedAtUnixMillis int64
|
||||
}
|
||||
|
||||
type EpisodeID ids.ID
|
||||
type Episode struct {
|
||||
ID EpisodeID
|
||||
PrincipalID string
|
||||
ExperienceRefs []ExperienceRecordID
|
||||
Summary string
|
||||
Outcome OutcomeClass
|
||||
RecordedAtUnixMillis int64
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package work
|
||||
|
||||
import "git.cin.su/m/Assistant/contracts/world"
|
||||
|
||||
type FreshnessRequirementMode string
|
||||
type FreshnessFallbackPolicy string
|
||||
|
||||
const (
|
||||
FreshnessAny FreshnessRequirementMode = "ANY"
|
||||
FreshnessPreferCurrent FreshnessRequirementMode = "PREFER_CURRENT"
|
||||
FreshnessRequireCurrent FreshnessRequirementMode = "REQUIRE_CURRENT"
|
||||
FreshnessRequireWithinAge FreshnessRequirementMode = "REQUIRE_WITHIN_AGE"
|
||||
FreshnessRequireVersionMatch FreshnessRequirementMode = "REQUIRE_VERSION_MATCH"
|
||||
FreshnessLiveRequired FreshnessRequirementMode = "LIVE_REQUIRED"
|
||||
FallbackAllowStaleDisclosure FreshnessFallbackPolicy = "ALLOW_STALE_WITH_DISCLOSURE"
|
||||
FallbackHypothesisOnly FreshnessFallbackPolicy = "USE_AS_HYPOTHESIS_ONLY"
|
||||
FallbackWaitForSource FreshnessFallbackPolicy = "WAIT_FOR_SOURCE"
|
||||
FallbackAskOwner FreshnessFallbackPolicy = "ASK_OWNER"
|
||||
FallbackStopUnknown FreshnessFallbackPolicy = "STOP_WITH_UNKNOWN"
|
||||
)
|
||||
|
||||
type TaskFreshnessRequirement struct {
|
||||
Mode FreshnessRequirementMode
|
||||
MaximumAgeMillis *int64
|
||||
RequiredVersionRefs []world.SemanticReference
|
||||
RevalidationRequired bool
|
||||
FallbackPolicy FreshnessFallbackPolicy
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
{"task_file":"dev/tasks/GEN2-005-world-identity-resolution-and-version-environment-bindings.json","task_id":"GEN2-005","task_revision":1}
|
||||
{"task_file":"dev/tasks/GEN2-009-build-memory-retrieval-fabric-as-rebuildable-projections.json","task_id":"GEN2-009","task_revision":1}
|
||||
@@ -0,0 +1,29 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"git.cin.su/m/Assistant/contracts/epistemics"
|
||||
"git.cin.su/m/Assistant/platform/ids"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func BuildEpisode(experiences []epistemics.ExperienceRecord, summary string, at int64) (epistemics.Episode, error) {
|
||||
if len(experiences) == 0 || strings.TrimSpace(summary) == "" || at < 1 {
|
||||
return epistemics.Episode{}, ErrInvalidExperience
|
||||
}
|
||||
refs := make([]epistemics.ExperienceRecordID, 0, len(experiences))
|
||||
outcome := epistemics.OutcomeUnknown
|
||||
for _, e := range experiences {
|
||||
if _, err := NewExperienceRecord(e); err != nil {
|
||||
return epistemics.Episode{}, err
|
||||
}
|
||||
refs = append(refs, e.ID)
|
||||
if e.ActualOutcome != epistemics.OutcomeSuccess {
|
||||
outcome = e.ActualOutcome
|
||||
}
|
||||
}
|
||||
id, err := ids.New()
|
||||
if err != nil {
|
||||
return epistemics.Episode{}, err
|
||||
}
|
||||
return epistemics.Episode{ID: epistemics.EpisodeID(id), ExperienceRefs: refs, Summary: summary, Outcome: outcome, RecordedAtUnixMillis: at}, nil
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package domain_test
|
||||
|
||||
import (
|
||||
"git.cin.su/m/Assistant/contracts/epistemics"
|
||||
"git.cin.su/m/Assistant/modules/epistemics/domain"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEpisodeIsRebuildableFromExperience(t *testing.T) {
|
||||
e := epistemics.ExperienceRecord{ID: "e", SourceKind: epistemics.ExperienceSourceInteraction, OriginalIntentID: "i", SourceUtteranceID: "u", HelpMethod: epistemics.HelpMethodFallback, ExpectedOutcome: epistemics.OutcomeSuccess, ActualOutcome: epistemics.OutcomeFailed, RecordedAtUnixMillis: 1}
|
||||
ep, err := domain.BuildEpisode([]epistemics.ExperienceRecord{e}, "failed attempt", 1)
|
||||
if err != nil || len(ep.ExperienceRefs) != 1 || ep.Outcome != epistemics.OutcomeFailed {
|
||||
t.Fatalf("episode=%#v err=%v", ep, err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package domain
|
||||
|
||||
import "git.cin.su/m/Assistant/contracts/epistemics"
|
||||
|
||||
// AssessFreshness receives the Work-owned requirement as primitive policy
|
||||
// inputs, keeping the Epistemics owner independent of Work package types.
|
||||
func AssessFreshness(applicability epistemics.TemporalApplicability, mode string, maximumAgeMillis *int64, nowMillis int64) epistemics.FreshnessAssessment {
|
||||
age := nowMillis - applicability.ObservedAtUnixMillis
|
||||
if age < 0 {
|
||||
age = 0
|
||||
}
|
||||
state := epistemics.FreshnessAssessmentCurrent
|
||||
reason := "observation is within applicability window"
|
||||
if applicability.ValidUntilUnixMillis != nil && nowMillis > *applicability.ValidUntilUnixMillis {
|
||||
state, reason = epistemics.FreshnessAssessmentStale, "valid-until elapsed"
|
||||
}
|
||||
if applicability.Volatility.HardStaleAfterMillis != nil && age > *applicability.Volatility.HardStaleAfterMillis {
|
||||
state, reason = epistemics.FreshnessAssessmentStale, "hard volatility window elapsed"
|
||||
}
|
||||
if applicability.Volatility.RevalidateAfterMillis != nil && age > *applicability.Volatility.RevalidateAfterMillis && state == epistemics.FreshnessAssessmentCurrent {
|
||||
state, reason = epistemics.FreshnessAssessmentAging, "revalidation window elapsed"
|
||||
}
|
||||
if maximumAgeMillis != nil && age > *maximumAgeMillis {
|
||||
state, reason = epistemics.FreshnessAssessmentStale, "task maximum age exceeded"
|
||||
}
|
||||
if mode == "LIVE_REQUIRED" {
|
||||
state, reason = epistemics.FreshnessAssessmentHistoricalOnly, "live source required"
|
||||
}
|
||||
return epistemics.FreshnessAssessment{SourceKnowledgeRef: "knowledge", TaskRef: "task", State: state, Reason: reason, AgeMillis: age, AssessedAtUnixMillis: nowMillis}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package domain_test
|
||||
|
||||
import (
|
||||
"git.cin.su/m/Assistant/contracts/epistemics"
|
||||
"git.cin.su/m/Assistant/modules/epistemics/domain"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFreshnessIsTaskRelative(t *testing.T) {
|
||||
hard := int64(100)
|
||||
app := epistemics.TemporalApplicability{ObservedAtUnixMillis: 1, Volatility: epistemics.VolatilitySpec{Mode: epistemics.VolatilityVersionBound, HardStaleAfterMillis: &hard}}
|
||||
current := domain.AssessFreshness(app, "ANY", nil, 50)
|
||||
historical := domain.AssessFreshness(app, "LIVE_REQUIRED", nil, 50)
|
||||
if current.State != epistemics.FreshnessAssessmentCurrent || historical.State != epistemics.FreshnessAssessmentHistoricalOnly {
|
||||
t.Fatalf("got %v and %v", current.State, historical.State)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"git.cin.su/m/Assistant/contracts/epistemics"
|
||||
"git.cin.su/m/Assistant/platform/ids"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var ErrInvalidKnowledge = errors.New("invalid epistemic knowledge record")
|
||||
|
||||
func ValidateProposition(value epistemics.Proposition) error {
|
||||
if value.ID == "" || value.Kind == "" || strings.TrimSpace(value.SubjectRef) == "" || (value.ObjectValue == "" && value.ObjectRef == "" && value.TextFallback == "") {
|
||||
return ErrInvalidKnowledge
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ValidateBeliefAssessment(value epistemics.BeliefAssessment) error {
|
||||
if value.ID == "" || value.ClaimID == "" || !value.Revision.Valid() || value.State == "" || value.ConfidenceMillis < 0 || value.ConfidenceMillis > 1000 || value.AssessedAtUnixMillis < 1 {
|
||||
return ErrInvalidKnowledge
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewBeliefAssessment(claim epistemics.ClaimID, confidence int64, state epistemics.BeliefAssessmentState, evidence []epistemics.EvidenceRef, at int64) (epistemics.BeliefAssessment, error) {
|
||||
id, err := ids.New()
|
||||
if err != nil {
|
||||
return epistemics.BeliefAssessment{}, err
|
||||
}
|
||||
value := epistemics.BeliefAssessment{ID: id, ClaimID: claim, Revision: ids.InitialRevision, State: state, ConfidenceMillis: confidence, EvidenceRefs: append([]epistemics.EvidenceRef(nil), evidence...), AssessedAtUnixMillis: at}
|
||||
if err := ValidateBeliefAssessment(value); err != nil {
|
||||
return epistemics.BeliefAssessment{}, err
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package domain_test
|
||||
|
||||
import (
|
||||
"git.cin.su/m/Assistant/contracts/epistemics"
|
||||
"git.cin.su/m/Assistant/modules/epistemics/domain"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestKnowledgeV2SeparatesPropositionAndReassessableBelief(t *testing.T) {
|
||||
p := epistemics.Proposition{ID: "p", Kind: epistemics.PropositionWorldFacet, SubjectRef: "world:database:a", ObjectValue: "1.6.28"}
|
||||
if err := domain.ValidateProposition(p); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
a, err := domain.NewBeliefAssessment("claim:a", 800, epistemics.BeliefAssessmentCurrent, []epistemics.EvidenceRef{"observation:a"}, 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
a.Revision++
|
||||
if err := domain.ValidateBeliefAssessment(a); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package retrieval
|
||||
|
||||
import "sort"
|
||||
|
||||
type Lane string
|
||||
|
||||
const (
|
||||
LaneSemantic Lane = "SEMANTIC"
|
||||
LaneEntity Lane = "ENTITY"
|
||||
LaneTemporal Lane = "TEMPORAL"
|
||||
LaneGoal Lane = "GOAL"
|
||||
LanePositiveExperience Lane = "POSITIVE_EXPERIENCE"
|
||||
LaneNegativeExperience Lane = "NEGATIVE_EXPERIENCE"
|
||||
LaneContradiction Lane = "CONTRADICTION"
|
||||
LaneSkill Lane = "SKILL"
|
||||
)
|
||||
|
||||
// RetrievalDocument is disposable read-side projection data. SourceRef and
|
||||
// Owner preserve provenance; this type never becomes canonical meaning.
|
||||
type RetrievalDocument struct {
|
||||
ID string
|
||||
SourceRef string
|
||||
Owner string
|
||||
PrincipalID string
|
||||
ContextScopeRef string
|
||||
VersionRef string
|
||||
Lane Lane
|
||||
Text string
|
||||
Relevance int
|
||||
Freshness int
|
||||
Confidence int
|
||||
Salience int
|
||||
Cost int
|
||||
}
|
||||
|
||||
type Query struct {
|
||||
PrincipalID string
|
||||
ContextScopeRef string
|
||||
VersionRef string
|
||||
Lanes []Lane
|
||||
Limit int
|
||||
}
|
||||
|
||||
func FilterAndRank(documents []RetrievalDocument, query Query) []RetrievalDocument {
|
||||
filtered := make([]RetrievalDocument, 0, len(documents))
|
||||
for _, doc := range documents {
|
||||
if doc.PrincipalID != query.PrincipalID || (query.ContextScopeRef != "" && doc.ContextScopeRef != query.ContextScopeRef) || (query.VersionRef != "" && doc.VersionRef != query.VersionRef) || !containsLane(query.Lanes, doc.Lane) {
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, doc)
|
||||
}
|
||||
sort.SliceStable(filtered, func(i, j int) bool {
|
||||
left := filtered[i].Relevance + filtered[i].Freshness + filtered[i].Confidence + filtered[i].Salience - filtered[i].Cost
|
||||
right := filtered[j].Relevance + filtered[j].Freshness + filtered[j].Confidence + filtered[j].Salience - filtered[j].Cost
|
||||
if left != right {
|
||||
return left > right
|
||||
}
|
||||
return filtered[i].ID < filtered[j].ID
|
||||
})
|
||||
if query.Limit > 0 && len(filtered) > query.Limit {
|
||||
filtered = filtered[:query.Limit]
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
func containsLane(lanes []Lane, lane Lane) bool {
|
||||
if len(lanes) == 0 {
|
||||
return true
|
||||
}
|
||||
for _, v := range lanes {
|
||||
if v == lane {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type ProjectionBuilder interface {
|
||||
Build() ([]RetrievalDocument, error)
|
||||
}
|
||||
|
||||
func Rebuild(builders ...ProjectionBuilder) ([]RetrievalDocument, error) {
|
||||
var result []RetrievalDocument
|
||||
for _, builder := range builders {
|
||||
docs, err := builder.Build()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, docs...)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package retrieval_test
|
||||
|
||||
import (
|
||||
"git.cin.su/m/Assistant/runtime/retrieval"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestScopeAndVersionFilterBeforeRanking(t *testing.T) {
|
||||
docs := []retrieval.RetrievalDocument{{ID: "wrong-company", PrincipalID: "a", ContextScopeRef: "b", VersionRef: "v", Lane: retrieval.LaneSemantic, Relevance: 100}, {ID: "right", PrincipalID: "a", ContextScopeRef: "a", VersionRef: "v", Lane: retrieval.LaneNegativeExperience, Relevance: 1}, {ID: "wrong-version", PrincipalID: "a", ContextScopeRef: "a", VersionRef: "old", Lane: retrieval.LaneSemantic, Relevance: 100}}
|
||||
got := retrieval.FilterAndRank(docs, retrieval.Query{PrincipalID: "a", ContextScopeRef: "a", VersionRef: "v", Lanes: []retrieval.Lane{retrieval.LaneSemantic, retrieval.LaneNegativeExperience}, Limit: 10})
|
||||
if len(got) != 1 || got[0].ID != "right" {
|
||||
t.Fatalf("got %#v", got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user