Exercise 2: A Real Registration-Order Bug, Reproduced & Fixed — Possible Solution ==================================================================== REPRODUCING THE BUG ------------------------------ router_broken = Router() router_broken.add_route( 'GET', '/users/', lambda **p: f"user detail {p['id']}", name='user_detail', ) router_broken.add_route( 'GET', '/users/new', lambda **p: 'user create form', name='user_create', ) status, handler, params, allowed = router_broken.resolve('GET', '/users/new') print(status, handler(**params)) # MATCH user detail new THE FIX ------------------------------ router_fixed = Router() router_fixed.add_route( 'GET', '/users/new', lambda **p: 'user create form', name='user_create', ) router_fixed.add_route( 'GET', '/users/', lambda **p: f"user detail {p['id']}", name='user_detail', ) status, handler, params, allowed = router_fixed.resolve('GET', '/users/new') print(status, handler(**params)) # MATCH user create form WHY THIS WORKS AS AN ANSWER ------------------------------ Both routers register the identical two routes with the identical handlers - only the order changes - and resolve() is called against the identical real path both times. The broken version's own general pattern matches "new" (an untyped [^/]+ segment matches any non-slash text) and, registered first, is returned before the loop ever reaches the dedicated /users/new route. Swapping the order lets the specific literal match first, exactly as Router.resolve()'s own top-to-bottom, first-match-wins scan requires.