Fix peak detection for Mann-Whitney U test by inverting P-value magnitude

In anomaly_peaks.go, invert the magnitude calculation for MannWhitneyU so that smaller P-values (which are more significant) result in larger magnitudes, correctly identifying them as peaks. Update caller in anomaly_bounds_refiner.go and add tests in anomaly_peaks_test.go.

Change-Id: I210175f89d306e6829ea052e0b4635ff548521b6
Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/1227656
Commit-Queue: Viktar Zinkou <viktarzinkou@google.com>
Reviewed-by: Ruslan Schalkenbajew <sruslan@google.com>
diff --git a/perf/go/regression/refiner/anomaly_bounds_refiner.go b/perf/go/regression/refiner/anomaly_bounds_refiner.go
index cc05db7..db80699 100644
--- a/perf/go/regression/refiner/anomaly_bounds_refiner.go
+++ b/perf/go/regression/refiner/anomaly_bounds_refiner.go
@@ -115,7 +115,7 @@
 // and delegates to refineGroup to determine the true boundaries of the anomaly. It returns a single
 // ConfirmedRegression that encompasses the refined anomalous range.
 func (r *AnomalyBoundsRefiner) mergeArea(cfg *alerts.Alert, area []*regression.RegressionDetectionResponse) *regression.ConfirmedRegression {
-	peakIdx := findPeaks(area)
+	peakIdx := findPeaks(area, cfg.Step)
 	return r.refineGroup(area, peakIdx, cfg)
 }
 
diff --git a/perf/go/regression/refiner/anomaly_peaks.go b/perf/go/regression/refiner/anomaly_peaks.go
index fe4aeca..0d0c3f1 100644
--- a/perf/go/regression/refiner/anomaly_peaks.go
+++ b/perf/go/regression/refiner/anomaly_peaks.go
@@ -4,6 +4,7 @@
 	"math"
 
 	"go.skia.org/infra/perf/go/regression"
+	"go.skia.org/infra/perf/go/types"
 )
 
 // PeakIndexes holds the indices of a peak in a regression group.
@@ -32,7 +33,7 @@
 //     is strictly greater than its immediate neighbors (or a flat region of equal magnitudes > neighbors).
 //  2. Global Max: The point with the highest StepFit regression magnitude in the group.
 //     If there's a flat region of max values, the center index of that flat region is returned.
-func findPeaks(group []*regression.RegressionDetectionResponse) PeakIndexes {
+func findPeaks(group []*regression.RegressionDetectionResponse, algo types.StepDetection) PeakIndexes {
 	n := len(group)
 	if n == 0 {
 		return PeakIndexes{}
@@ -43,7 +44,13 @@
 			return -1.0 // Implicitly smaller than any valid magnitude (>=0)
 		}
 		// Validated in validateInput to have Summary/Clusters/StepFit
-		return math.Abs(float64(group[i].Summary.Clusters[0].StepFit.Regression))
+		mag := math.Abs(float64(group[i].Summary.Clusters[0].StepFit.Regression))
+		if algo == types.MannWhitneyU {
+			// For Mann-Whitney, smaller P-value is better.
+			// Invert it so that smaller P-values give larger magnitudes.
+			return 1.0 - mag
+		}
+		return mag
 	}
 
 	localPeaks := findLocalPeaks(n, getMag)
diff --git a/perf/go/regression/refiner/anomaly_peaks_test.go b/perf/go/regression/refiner/anomaly_peaks_test.go
index 5f6cec7..2ab0ebd 100644
--- a/perf/go/regression/refiner/anomaly_peaks_test.go
+++ b/perf/go/regression/refiner/anomaly_peaks_test.go
@@ -8,6 +8,7 @@
 	"go.skia.org/infra/perf/go/dataframe"
 	"go.skia.org/infra/perf/go/regression"
 	"go.skia.org/infra/perf/go/stepfit"
+	"go.skia.org/infra/perf/go/types"
 	"go.skia.org/infra/perf/go/ui/frame"
 )
 
@@ -110,7 +111,62 @@
 
 	for _, tc := range tests {
 		t.Run(tc.name, func(t *testing.T) {
-			assert.Equal(t, tc.expected, findPeaks(tc.input))
+			assert.Equal(t, tc.expected, findPeaks(tc.input, types.AbsoluteStep))
+		})
+	}
+}
+
+func TestFindPeaks_MannWhitney_ReturnsStructuredPeaks(t *testing.T) {
+	// Helper to create a response with a specific regression value (P-value)
+	r := func(val float64) *regression.RegressionDetectionResponse {
+		return &regression.RegressionDetectionResponse{
+			Frame: &frame.FrameResponse{DataFrame: &dataframe.DataFrame{}},
+			Summary: &clustering2.ClusterSummaries{
+				Clusters: []*clustering2.ClusterSummary{
+					{
+						StepFit: &stepfit.StepFit{
+							Regression: float32(val),
+							Status:     stepfit.LOW,
+						},
+						StepPoint: &dataframe.ColumnHeader{Offset: 100},
+						Keys:      []string{"k"},
+					},
+				},
+			},
+		}
+	}
+
+	tests := []struct {
+		name     string
+		input    []*regression.RegressionDetectionResponse
+		expected PeakIndexes
+	}{
+		{
+			name:  "Single Peak (Smallest P-value is peak)",
+			input: []*regression.RegressionDetectionResponse{r(0.05), r(0.01), r(0.05)},
+			expected: PeakIndexes{
+				LeftIndex: 1, RightIndex: 1, MaxIndex: 1,
+			},
+		},
+		{
+			name:  "Flat Peak",
+			input: []*regression.RegressionDetectionResponse{r(0.05), r(0.01), r(0.01), r(0.05)},
+			expected: PeakIndexes{
+				LeftIndex: 1, RightIndex: 2, MaxIndex: 2,
+			},
+		},
+		{
+			name:  "Multiple Peaks - Global Max Middle",
+			input: []*regression.RegressionDetectionResponse{r(0.05), r(0.03), r(0.05), r(0.001), r(0.05), r(0.03), r(0.05)},
+			expected: PeakIndexes{
+				LeftIndex: 1, RightIndex: 5, MaxIndex: 3,
+			},
+		},
+	}
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			assert.Equal(t, tc.expected, findPeaks(tc.input, types.MannWhitneyU))
 		})
 	}
 }