Gap — Surface-B server ranking (the recorded fallback for client-side ranking)
A record, not a proposal. Spec 035 moved legendary ranking into the browser (Wave 3 of the gw2.app alignment epic) and retired the server-side legendaries/ranking.service.ts account-scan path. This file records the fallback that spec deliberately left out of scope, so a future session starts from the decision instead of rediscovering it.
What was decided
Ranking is computed client-side: for each of the 21 Gen-1 legendaries the browser fetches the Surface-A priceless tree, prices it browser→ArenaNet, and folds it through the shared @gw2priory/recipe-graph engine against a browser-built four-source owned-items map. No server ranking endpoint exists; the AI layer (assistant + MCP) is stateless-per-request and holds no key at rest.
The fallback, and when it triggers
If client-side ranking is ever measured too heavy on a mid-range device — the realistic tail is an account with a very large character count (the owned scan fans out one request per character) or a cold Surface-A tree cache — the upgrade path is a Surface-B server ranking endpoint:
- Per-request only: it receives the caller's API key or a precomputed account snapshot per call, computes, returns, and persists nothing. Response
private, no-store. The key never lands at rest, in a log, or in a cache. - It does not reintroduce the retired always-on account scan or any per-user caching — that would break the epic invariant (anything per-user is stateless and never cached).
- The retired
ranking.service.tslogic (resolve 21 graphs → price the deduped union in one call → fold through the shared engine) is the reference; git history at spec 035's parent (a14d4bb) has it.
Evidence this is a tail, not the common case (spec 035 research V1)
- ArenaNet is CORS-open and rate-limited per source IP (
x-rate-limit-limit: 600); the browser spends the user's own budget with no 5 req/s self-throttle (unlike our origin's token bucket). - Per-request latency ~0.1–0.8s (CLI probe), and the
4 + N-character account requests multiplex concurrently over HTTP/2 → a few seconds wall-clock for typical and even 19-character accounts, well under the 31s the throttled server path measured (mcp.tools.ts:239). - So the fallback is an insurance policy for the pathological tail, not an expected need.
Status
Not built. Trigger: a measured client-ranking run past an interactive budget on a real mid-range device / large account. Until then, YAGNI — the browser path stands.