Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 8 additions & 16 deletions internal/api/handler_recommendations.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"time"

"github.com/LeanerCloud/cloud-commitments-go/pkg/common"
"github.com/LeanerCloud/cloud-commitments-go/pkg/exchange"
"github.com/LeanerCloud/cloud-commitments-platform/internal/auth"
"github.com/LeanerCloud/cloud-commitments-platform/internal/config"
"github.com/aws/aws-lambda-go/events"
Expand Down Expand Up @@ -386,28 +387,19 @@ func (h *Handler) buildRecommendationDetail(ctx context.Context, rec *config.Rec
}
}

// Confidence bucket cut-offs for the recommendation drawer badge. They must
// stay equal to exchange.ConfidenceHighSavingsUSD, exchange.ConfidenceHighMinCount
// and exchange.ConfidenceMediumSavingsUSD in cloud-commitments-go pkg/exchange,
// which score the reshape ranking the badge accompanies. Those exported
// constants are newer than the pkg version pinned in go.mod; once the pin is
// bumped past them, alias these to the exchange constants (#343).
const (
confidenceHighSavingsUSD = 200.0 // USD per month, high bucket
confidenceHighMinCount = 3 // instances, high bucket
confidenceMediumSavingsUSD = 50.0 // USD per month, medium bucket
)

// confidenceBucketFor mirrors the heuristic that previously lived
// client-side in frontend/src/recommendations.ts. Centralizing it on
// the server lets future provider-specific tuning land in one place
// without a frontend deploy. Thresholds intentionally match the original
// shim 1:1 so the drawer label doesn't visibly shift on rollout.
//
// high = savings >= confidenceHighSavingsUSD AND count >= confidenceHighMinCount
// medium = savings >= confidenceMediumSavingsUSD
// high = savings >= exchange.ConfidenceHighSavingsUSD AND count >= exchange.ConfidenceHighMinCount
// medium = savings >= exchange.ConfidenceMediumSavingsUSD
// low = otherwise
//
// The cut-offs come from pkg/exchange, which scores the reshape ranking the
// badge accompanies, so the two cannot drift apart (#343).
//
// A count below 1 (missing) is clamped to 1, so savings alone decide between
// medium and low. This deliberately differs from the exchange ranking, which
// returns a neutral score for a zero count: a badge must always show a
Expand All @@ -416,10 +408,10 @@ func confidenceBucketFor(savings float64, count int) string {
if count < 1 {
count = 1
}
if savings >= confidenceHighSavingsUSD && count >= confidenceHighMinCount {
if savings >= exchange.ConfidenceHighSavingsUSD && count >= exchange.ConfidenceHighMinCount {
return "high"
}
if savings >= confidenceMediumSavingsUSD {
if savings >= exchange.ConfidenceMediumSavingsUSD {
return "medium"
}
return "low"
Expand Down
Loading