diff --git a/changelog.d/fixes/11595-combo-success-rate-scale.md b/changelog.d/fixes/11595-combo-success-rate-scale.md
new file mode 100644
index 0000000000..b9802ee5a5
--- /dev/null
+++ b/changelog.d/fixes/11595-combo-success-rate-scale.md
@@ -0,0 +1 @@
+- **fix(dashboard):** Provider Stats now displays combo success rates on their native 0–100 percentage scale instead of multiplying them twice ([#11595](https://github.com/diegosouzapw/OmniRoute/pull/11595)) — thanks @pacocartones
diff --git a/src/app/(dashboard)/dashboard/provider-stats/page.tsx b/src/app/(dashboard)/dashboard/provider-stats/page.tsx
index bdc1e54cee..96e22cf9b5 100644
--- a/src/app/(dashboard)/dashboard/provider-stats/page.tsx
+++ b/src/app/(dashboard)/dashboard/provider-stats/page.tsx
@@ -9,8 +9,10 @@
import { useState, useEffect, useCallback, Fragment } from "react";
import { useTranslations } from "next-intl";
-import { Card } from "@/shared/components";
+
import { useProviderNodeMap, resolveProviderName } from "@/lib/display/useProviderNodeMap";
+import { formatComboSuccessRate } from "@/lib/usage/providerStatsFormatters";
+import { Card } from "@/shared/components";
interface ProviderStat {
provider: string;
@@ -493,7 +495,7 @@ export default function ProviderStatsPage() {
{typeof m.successRate === "number"
- ? `${(m.successRate * 100).toFixed(1)}%`
+ ? formatComboSuccessRate(m.successRate)
: "—"}
|
diff --git a/src/lib/usage/providerStatsFormatters.ts b/src/lib/usage/providerStatsFormatters.ts
new file mode 100644
index 0000000000..d61622e852
--- /dev/null
+++ b/src/lib/usage/providerStatsFormatters.ts
@@ -0,0 +1,3 @@
+export function formatComboSuccessRate(successRatePercent: number): string {
+ return `${successRatePercent.toFixed(1)}%`;
+}
diff --git a/tests/unit/provider-stats-formatters.test.ts b/tests/unit/provider-stats-formatters.test.ts
new file mode 100644
index 0000000000..7f36e5a1fb
--- /dev/null
+++ b/tests/unit/provider-stats-formatters.test.ts
@@ -0,0 +1,38 @@
+import assert from "node:assert/strict";
+import fs from "node:fs";
+import path from "node:path";
+import test from "node:test";
+
+import {
+ getComboMetrics,
+ recordComboRequest,
+ resetAllComboMetrics,
+} from "../../open-sse/services/comboMetrics.ts";
+import { formatComboSuccessRate } from "../../src/lib/usage/providerStatsFormatters.ts";
+
+test.after(resetAllComboMetrics);
+
+test("formatComboSuccessRate preserves the producer's 0-100 percentage scale", () => {
+ resetAllComboMetrics();
+ recordComboRequest("format-test", "openai/gpt-4o-mini", {
+ success: true,
+ latencyMs: 10,
+ });
+
+ const metrics = getComboMetrics("format-test");
+ assert.ok(metrics);
+ assert.equal(metrics.successRate, 100);
+ assert.equal(formatComboSuccessRate(metrics.successRate), "100.0%");
+ assert.equal(formatComboSuccessRate(50), "50.0%");
+ assert.equal(formatComboSuccessRate(0), "0.0%");
+});
+
+test("Provider Stats renders combo metrics through the percentage-scale formatter", () => {
+ const source = fs.readFileSync(
+ path.resolve("src/app/(dashboard)/dashboard/provider-stats/page.tsx"),
+ "utf8"
+ );
+
+ assert.match(source, /formatComboSuccessRate\(m\.successRate\)/);
+ assert.doesNotMatch(source, /m\.successRate\s*\*\s*100/);
+});