SIGN IN SIGN UP

fix: align pool display semantics with what routing actually does

Three review findings, all the same defect class — the overview asserted
routing behaviour the proxy does not exhibit:

The observed routing order recorded only the FIRST account selection. When
every combo slot fails, proxy.ts re-selects (step 10) and that second list
serves the request, so the table showed the order that failed while calling
it the last decision the proxy made.

Pool grouping keyed on the raw weekly_scoped display name, but routing keys
on getModelFamily(display_name) — two display names for one routable family
would have split into two pools that no request can distinguish. And
extractWeeklyScoped read only the FIRST matching row via find(), while
isAccountExhaustedForModel requires EVERY row of a family to be exhausted,
so payload order decided the displayed utilization and exhaustion state.

Both selection points now go through recordSelectedOrder, which derives the
family once, skips unknown models and empty lists, and never throws into the
request path; last write wins, so the serving order is the one displayed.
Pool families are keyed by getModelFamily with a fallback to the trimmed,
lowercased name so an unrecognized family surfaces as its own pool instead
of vanishing, and scoped rows are aggregated: percent is the maximum across
rows (the binding constraint), reset the earliest among those, and
family_exhausted requires every row to be at 100% WITH a future reset —
matching the backend's fail-open guard against stale telemetry.

Pool ids move from `scoped:Fable` to `scoped:fable`, which is also the
localStorage key for row expansion, so expanded rows collapse once after
this update.

The future-reset condition came from an independent implementation of the
same three findings, written without sight of this one and compared
afterwards; it was the one case this version had missed.
M
Matthias Breddin committed
7549abc9aa56e239df536c930829c974f8a7789c
Parent: ef75b8e