Opening the Node detail page for a well-connected contact could hang for
tens of seconds. The cost was topology._best_routes: a best-first walk over
partial paths to the target. On a densely-heard graph every wandering prefix
through the core is cheaper than the one weak link a distant node sits behind,
so the frontier floods the core — millions of dead-end prefixes — before it
ever reaches the target. Measured against the live DB, a single node took 28 s
(4.4M heap pushes), and scenarios() runs twice per page open.
Replace it with Yen's k-shortest-loopless-paths: find the shortest route once
by Dijkstra, then derive each next-shortest by rerouting around one edge of the
last. The work is polynomial in the graph size however dense the core. Verified
against the old search over the real DB: identical k-cheapest costs on all 148
nodes it could finish, and the worst node drops from 28 s to 22 ms (~1250x),
with the full 5 alternatives still found. Tie-ordering among equal-cost paths
may differ, which is moot — scenarios() re-scores every candidate by weakest
link anyway.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>