package trust import ( "errors" "sort" "provenance/internal/domain" ) const ( DefaultStateLimit = 100000 DefaultEdgeLimit = 1000000 MaxDepth = 10 ) var ErrLimit = errors.New("trust traversal resource limit exceeded") type Status string const ( UnknownStatus Status = "unknown" SelfStatus Status = "self" BlockedStatus Status = "blocked" CalculatedStatus Status = "calculated" ) type Result struct { Status Status `json:"status"` Score *float64 `json:"score"` Path []string `json:"path,omitempty"` PathScores []PathScore `json:"path_scores,omitempty"` } type PathScore struct { DID string `json:"did"` Assertion *float64 `json:"assertion"` Source string `json:"source,omitempty"` ListURI string `json:"list_uri,omitempty"` Score float64 `json:"score"` Comment string `json:"comment,omitempty"` } type Limits struct { States int Edges int Penalty float64 } // Select one assertion per pair so that fallback never overrides an explicit score. func Select(vouches []domain.Vouch, tag string, mode domain.Mode) []domain.Vouch { // Store input indexes instead of another full copy of every selected assertion. chosen := make(map[[2]string]int, len(vouches)) for index, v := range vouches { if domain.SoftSource(v.Source) && mode == domain.Tagged { continue } if v.Tag != tag && !(mode == domain.Fallback && v.Tag == "") { continue } key := [2]string{v.Author, v.Subject} previous, exists := chosen[key] if !exists || preferVouch(v, vouches[previous], tag) { chosen[key] = index } } result := make([]domain.Vouch, 0, len(chosen)) for _, index := range chosen { result = append(result, vouches[index]) } sort.Slice(result, func(i, j int) bool { if result[i].Author != result[j].Author { return result[i].Author < result[j].Author } return result[i].Subject < result[j].Subject }) return result } func preferVouch(candidate, previous domain.Vouch, tag string) bool { if vouchRank(candidate) != vouchRank(previous) { return vouchRank(candidate) > vouchRank(previous) } if candidate.Tag != previous.Tag { return candidate.Tag == tag } return candidate.RecordKey < previous.RecordKey } type selectionRank int const ( followRank selectionRank = iota softBlockRank explicitRank ) func vouchRank(v domain.Vouch) selectionRank { if v.Source == domain.FollowCollection { return followRank } if v.Source == domain.BlockCollection || v.Source == domain.ListBlockCollection { return softBlockRank } return explicitRank }