fix(router): preserve selected connection identity (#11530)

Validated in a combined 10-PR batch worktree off release/v3.8.51 tip.
- Focused test: tests/unit/router-strategies.test.ts — 22/22 pass
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity gates — all OK
- Full-repo lint: 503 pre-existing problems confirmed identical on the pure release/v3.8.51 tip — unrelated to this diff

⚠️ base-red inherited: #11449

Thanks for carrying the winning connectionId through cost/latency/SLA/LKGP so duplicate accounts dispatch through the connection actually ranked.
This commit is contained in:
Paco Cartones
2026-08-25 18:12:15 +02:00
committed by GitHub
parent eb9b4cec54
commit 3804ffb6ff
4 changed files with 77 additions and 2 deletions

View File

@@ -0,0 +1 @@
- Fixed auto-router strategies preserving the selected connection through ranking and dispatch when multiple connections share the same provider and model.

View File

@@ -115,7 +115,7 @@ class CostStrategyImpl implements RouterStrategy {
readonly name = "cost";
readonly description = "Always selects cheapest available provider (by costPer1MTokens)";
select(pool: ProviderCandidate[], context: RoutingContext): RoutingDecision {
select(pool: ProviderCandidate[], _context: RoutingContext): RoutingDecision {
const healthy = pool.filter((c) => c.circuitBreakerState !== "OPEN");
const candidates = healthy.length > 0 ? healthy : pool;
const sorted = [...candidates].sort((a, b) => a.costPer1MTokens - b.costPer1MTokens);
@@ -128,6 +128,7 @@ class CostStrategyImpl implements RouterStrategy {
reason: `CostStrategy: cheapest at $${best.costPer1MTokens.toFixed(3)}/1M tokens`,
candidatesConsidered: candidates.length,
finalScore: best.costPer1MTokens === 0 ? 1.0 : 1 / best.costPer1MTokens,
connectionId: best.connectionId,
};
}
}
@@ -139,7 +140,7 @@ class LatencyStrategyImpl implements RouterStrategy {
readonly description =
"Prioritizes the fastest reliable provider-model pair using TTFT, TPS, E2E latency, health, fail rate, and stability";
select(pool: ProviderCandidate[], context: RoutingContext): RoutingDecision {
select(pool: ProviderCandidate[], _context: RoutingContext): RoutingDecision {
const ranked = rankBySpeed(pool.map(toSpeedCandidate));
const winner = ranked[0];
if (!winner) {
@@ -153,6 +154,7 @@ class LatencyStrategyImpl implements RouterStrategy {
reason: latencyDecisionReason(winner),
candidatesConsidered: ranked.length,
finalScore: winner.score,
connectionId: winner.connectionId,
};
}
}
@@ -292,6 +294,7 @@ class SLAStrategyImpl implements RouterStrategy {
reason: `SLAStrategy: p95=${best.candidate.p95LatencyMs}ms/${policy.targetP95Ms}ms, errorRate=${(best.candidate.errorRate * 100).toFixed(2)}%/${(policy.maxErrorRate * 100).toFixed(2)}%, cost=$${best.candidate.costPer1MTokens.toFixed(3)}/1M${fallbackNote}`,
candidatesConsidered: candidates.length,
finalScore: best.score,
connectionId: best.candidate.connectionId,
};
}
}
@@ -320,6 +323,7 @@ class LKGPStrategyImpl implements RouterStrategy {
reason: `LKGP: using last known good provider ${best.provider}`,
candidatesConsidered: 1,
finalScore: 1.0,
connectionId: best.connectionId,
};
}
}

View File

@@ -60,6 +60,7 @@ export interface SpeedFactors {
export interface SpeedRankedCandidate {
provider: string;
model: string;
connectionId?: string;
/** Final composite score in [0..1]; higher is faster+more-reliable. */
score: number;
factors: SpeedFactors;
@@ -309,6 +310,7 @@ export function rankBySpeed(
return {
provider: candidate.provider,
model: candidate.model,
connectionId: candidate.connectionId,
score,
factors,
metrics,

View File

@@ -45,6 +45,17 @@ test("cost — selects the cheapest healthy candidate", () => {
assert.equal(d.strategy, "cost");
});
test("cost — preserves the selected connection when provider and model are shared", () => {
const pool = [
cand({ provider: "shared", model: "shared/m", connectionId: "conn-a", costPer1MTokens: 5 }),
cand({ provider: "shared", model: "shared/m", connectionId: "conn-b", costPer1MTokens: 1 }),
];
const decision = getStrategy("cost").select(pool, ctx);
assert.equal(decision.connectionId, "conn-b");
});
test("cost — excludes OPEN-breaker candidates even if cheaper", () => {
const pool = [
cand({ provider: "cheap-open", costPer1MTokens: 0.1, circuitBreakerState: "OPEN" }),
@@ -107,6 +118,31 @@ test("latency — uses TTFT, TPS, and E2E metrics to pick the fastest provider-m
assert.match(decision.reason, /tps=120/);
});
test("latency — preserves the selected connection through speed ranking", () => {
const pool = [
cand({
provider: "shared",
model: "shared/m",
connectionId: "conn-a",
p95LatencyMs: 900,
avgTtftMs: 400,
avgE2ELatencyMs: 1_200,
}),
cand({
provider: "shared",
model: "shared/m",
connectionId: "conn-b",
p95LatencyMs: 100,
avgTtftMs: 30,
avgE2ELatencyMs: 300,
}),
];
const decision = getStrategy("latency").select(pool, ctx);
assert.equal(decision.connectionId, "conn-b");
});
test("latency — failure rate can outweigh excellent raw speed", () => {
const pool = [
cand({
@@ -148,6 +184,25 @@ test("sla-aware — prefers a candidate meeting the p95/error SLOs", () => {
assert.equal(d.strategy, "sla-aware");
});
test("sla-aware — preserves the selected connection for dispatch", () => {
const pool = [
cand({
provider: "shared",
model: "shared/m",
connectionId: "conn-a",
p95LatencyMs: 5_000,
}),
cand({ provider: "shared", model: "shared/m", connectionId: "conn-b", p95LatencyMs: 300 }),
];
const decision = getStrategy("sla-aware").select(pool, {
taskType: "default",
sla: { targetP95Ms: 2_000 },
});
assert.equal(decision.connectionId, "conn-b");
});
test("sla-aware — 'sla' alias resolves to sla-aware", () => {
assert.equal(getStrategy("sla").name, "sla-aware");
});
@@ -175,6 +230,19 @@ test("lkgp — returns the last known good provider when healthy", () => {
assert.equal(d.strategy, "lkgp");
});
test("lkgp — preserves the connection of the selected last-known-good candidate", () => {
const pool = [
cand({ provider: "shared", connectionId: "conn-b" }),
cand({ provider: "other", connectionId: "conn-a" }),
];
const decision = getStrategy("lkgp").select(pool, {
taskType: "default",
lastKnownGoodProvider: "shared",
});
assert.equal(decision.connectionId, "conn-b");
});
test("lkgp — falls back to rules when the LKGP is OPEN", () => {
const pool = [cand({ provider: "x" }), cand({ provider: "y", circuitBreakerState: "OPEN" })];
const d = getStrategy("lkgp").select(pool, {