package maximizer // ScoreWeights controls the balance between safety and business utility. type ScoreWeights struct { Safety float64 `json:"safety"` Utility float64 `json:"utility"` } // DefaultWeights prioritizes business utility slightly over safety margin // since the optimizer already ensures compliance. var DefaultWeights = ScoreWeights{Safety: 0.4, Utility: 0.6} // dimensionBusinessWeight indicates how much business value each dimension // contributes. Higher = more costly to change for the business. var dimensionBusinessWeight = map[string]int{ "automation_level": 15, "decision_binding": 12, "deployment_scope": 10, "model_type": 8, "decision_impact": 7, "explainability": 5, "data_type": 5, "human_in_loop": 5, "legal_basis": 4, "domain": 3, "risk_classification": 3, "transparency_required": 2, "logging_required": 2, } // ComputeSafetyScore returns 0-100 where 100 = completely safe (no restrictions). // Decreases with each RESTRICTED or FORBIDDEN zone. func ComputeSafetyScore(eval *EvaluationResult) int { if eval == nil { return 0 } total := len(allDimensions) safe := 0 for _, zi := range eval.ZoneMap { if zi.Zone == ZoneSafe { safe++ } } if total == 0 { return 100 } return (safe * 100) / total } // ComputeUtilityScore returns 0-100 where 100 = no changes from original. // Decreases based on the business weight of each changed dimension. func ComputeUtilityScore(original, variant *DimensionConfig) int { if original == nil || variant == nil { return 0 } deltas := original.Diff(variant) if len(deltas) == 0 { return 100 } maxCost := 0 for _, w := range dimensionBusinessWeight { maxCost += w } cost := 0 for _, d := range deltas { w := dimensionBusinessWeight[d.Dimension] if w == 0 { w = 3 // default } cost += w } if cost >= maxCost { return 0 } return 100 - (cost*100)/maxCost } // ComputeCompositeScore combines safety and utility into a single ranking score. func ComputeCompositeScore(safety, utility int, weights ScoreWeights) float64 { return weights.Safety*float64(safety) + weights.Utility*float64(utility) }