Files
m 30443027a6
CI / test (push) Failing after 37s
CI / test (pull_request) Failing after 32s
feat: add evidence-based adaptive model rating
2026-08-22 23:42:10 +03:00

81 lines
2.9 KiB
Go

package domain
import (
"errors"
"slices"
"sort"
"git.cin.su/m/Assistant/contracts/capability"
)
var ErrInvalidFleetReadiness = errors.New("invalid fleet readiness")
func BuildFleetReadiness(observedAt int64, members []capability.FleetMember) (capability.FleetReadiness, error) {
if observedAt < 1 || len(members) == 0 {
return capability.FleetReadiness{}, ErrInvalidFleetReadiness
}
result := capability.FleetReadiness{ObservedAtUnixMillis: observedAt, Members: append([]capability.FleetMember(nil), members...), FallbackTier: capability.FleetTierLifeboat}
seen := map[capability.FleetTier]bool{}
for i := range result.Members {
member := &result.Members[i]
if member.ProviderInstanceID == "" || member.ModelDescriptorID == "" || !validFleetTier(member.Tier) || seen[member.Tier] && member.Ready {
return capability.FleetReadiness{}, ErrInvalidFleetReadiness
}
if member.Ready {
seen[member.Tier] = true
}
}
for _, tier := range []capability.FleetTier{capability.FleetTierFast, capability.FleetTierMedium, capability.FleetTierHeavy, capability.FleetTierLifeboat} {
if seen[tier] {
result.ReadyTiers = append(result.ReadyTiers, tier)
}
}
return result, nil
}
func SelectFleetTier(readiness capability.FleetReadiness, preferred capability.FleetTier) (capability.FleetTier, error) {
if readiness.ObservedAtUnixMillis < 1 || len(readiness.Members) == 0 || !validFleetTier(readiness.FallbackTier) {
return "", ErrInvalidFleetReadiness
}
if !validFleetTier(preferred) {
return "", ErrInvalidFleetReadiness
}
for _, tier := range fleetFailoverOrder(preferred) {
if slices.Contains(readiness.ReadyTiers, tier) {
return tier, nil
}
}
if slices.Contains(readiness.ReadyTiers, readiness.FallbackTier) {
return readiness.FallbackTier, nil
}
return "", ErrInvalidFleetReadiness
}
func fleetFailoverOrder(preferred capability.FleetTier) []capability.FleetTier {
switch preferred {
case capability.FleetTierHeavy:
return []capability.FleetTier{capability.FleetTierHeavy, capability.FleetTierMedium, capability.FleetTierFast}
case capability.FleetTierMedium:
return []capability.FleetTier{capability.FleetTierMedium, capability.FleetTierFast}
case capability.FleetTierFast:
return []capability.FleetTier{capability.FleetTierFast, capability.FleetTierMedium, capability.FleetTierHeavy}
case capability.FleetTierLifeboat:
return []capability.FleetTier{capability.FleetTierLifeboat}
default:
return nil
}
}
func validFleetTier(value capability.FleetTier) bool {
return value == capability.FleetTierFast || value == capability.FleetTierMedium || value == capability.FleetTierHeavy || value == capability.FleetTierLifeboat
}
func SortFleetMembers(members []capability.FleetMember) {
sort.SliceStable(members, func(i, j int) bool {
if members[i].Tier != members[j].Tier {
return members[i].Tier < members[j].Tier
}
return members[i].ProviderInstanceID < members[j].ProviderInstanceID
})
}