Changed
- Router
scoreis now a pure latency+uptime composite (issue #120 hardening). Previously the routing score was0.4*latency + 0.4*uptime + 0.2*priorityBonus— mixing explicit priority into the score could mislead tiebreakers and dashboards, because the routing comparator ingetRoutingCandidatesalready enforces priority authoritatively.scoreCandidates()now exposesscore = 0.5*latency + 0.5*uptime(pure model quality, normalized to[0, 1]), andpriorityBonusis kept as a separate field for back-compat dashboards and legacy UIs. The remaininglatencyWeight/uptimeWeightwere rebalanced to0.5 / 0.5so the score stays in[0, 1]after priority is removed. Applies uniformly to CLI, Web Dashboard, and Desktop surfaces because the change lives in shared core (src/core/router-daemon.js+src/core/config.js).
Fixed
- HALF_OPEN recovery is now respected by the priority-first comparator (issue #120 regression test). The v0.5.36 fix changed
getRoutingCandidatesto sort by explicit priority before circuit state, but had no test for the exact scenario from the issue screenshot: a high-priority model sitting inHALF_OPENrecovery vs. a lower-priorityCLOSEDmodel. Added a regression test that pinsruntime.circuit.get(key).state = 'HALF_OPEN'for priority#1while priority#5staysCLOSED, then verifies both/stats.routingOrder[0]and the actual chat-completions response target the HALF_OPEN priority-#1 model — locking in the fix so it can't silently regress. - Score tiebreaker is deterministic when two models share the same priority (issue #120 regression test). Added a second regression test that puts two models at the same explicit priority (rare but reachable via direct API or auto-heal) with deliberately asymmetric probe data — fast groq (80 ms) vs. slow nvidia (2000 ms) — and verifies that the higher-score model wins
routingOrder[0]. This locks in the new pure-latency+uptime score as the deterministic tiebreaker for same-priority same-state candidates, preventing future regressions where Map iteration order or stale priority data could leak back into routing.
Docs
DEFAULT_ROUTER_SETTINGS.scoring.priorityWeightmarked as preserved-for-back-compat. The field still round-trips throughnormalizeRouterScoring()so user configs that customize it are not silently dropped on next save, but it is now ignored by the runtimescoreCandidates(). Will be removed in a future major bump. Comment block insrc/core/config.jsdocuments the rationale.
Tests
- +2 new tests for issue #120 (
test/test.js,router daemon integration hardeningsuite):keeps a higher-priority HALF_OPEN model above a lower-priority CLOSED oneandbreaks score ties deterministically by latency/uptime, not priority. Test count moves from 540 → 542, all passing.