diff --git a/src/dashboard/public/app.js b/src/dashboard/public/app.js
index 6ff30c5..ceb4d17 100644
--- a/src/dashboard/public/app.js
+++ b/src/dashboard/public/app.js
@@ -1421,7 +1421,8 @@ async function renderFailoverTuning() {
5xx feeds breaker
burst-429 feeds breaker
quota-429 → cooldown + failover
- other 4xx count-only
+ throttle-403 → short cooldown + failover
+ other 4xx count-only
transport errors never trip
local outage never burns
diff --git a/src/proxy/server.ts b/src/proxy/server.ts
index bf4a93d..d21908b 100644
--- a/src/proxy/server.ts
+++ b/src/proxy/server.ts
@@ -558,13 +558,17 @@ export class ProxyServer {
if (!repeatedServerError) {
this.keyManager.markError(key.id)
}
- this.keyManager.recordRequest(key.id, {
- statusCode: upstreamRes.status,
- durationMs: duration,
- model: prepared.model,
- sessionId: upstreamSessionId ?? sessionKey ?? null,
- successful: false,
- })
+ if (attempt < maxAttempts - 1) {
+ // Counted here; on the last attempt the tail recordRequest
+ // below counts the verbatim 5xx once (no double-count).
+ this.keyManager.recordRequest(key.id, {
+ statusCode: upstreamRes.status,
+ durationMs: duration,
+ model: prepared.model,
+ sessionId: upstreamSessionId ?? sessionKey ?? null,
+ successful: false,
+ })
+ }
attemptedKeyIds.add(key.id)
if (circuitState === CircuitState.OPEN) {