Backend
- api/routes.rs models the Babel-style route shape; metric uses an
untagged enum to round-trip both numeric hop counts and the
literal "infinite" string the daemon emits for poisoned routes
- routes_snapshot() runs the three GETs concurrently with try_join
so the snapshot is internally consistent
- poller spawns a second 5s loop emitting routes://updated; both
loops are owned by the Poller and aborted together on stop_daemon
Frontend
- routes store mirrors the snapshot shape; tabbed view (radix-vue)
with selected, fallback and queried lists
- RouteTable component shared by selected/fallback; metric column
is colour-coded (0 green, low neutral, high yellow, infinite red)
- Queried subnets show a live `expires in 12s` countdown driven by
a 1Hz tick ref instead of mutating the store