Phase 2 — raise GET_DEFAULT_MAX_HOPS 3→4 for hybrid GET best-execution #323

Closed
opened 2026-06-05 08:23:01 +00:00 by Brouie · 21 comments
Brouie commented 2026-06-05 08:23:01 +00:00 (Migrated from gitlab.com)

Summary

Bump GET_DEFAULT_MAX_HOPS from 3 to 4 so the hybrid GET best-execution solver discovers and prices 4-hop routes, matching the pool-only escape hatch (GET_POOL_ONLY_MAX_HOPS = 4) and the on-chain router cap (MAX_HOPS = 4). Right now the default hybrid GET path is one hop short of what the router can actually execute, so any token pair whose only viable route is 4 hops is reachable via pool_only=true but never gets a hybrid (book + pool) split quote.

This is Phase 2 of the #279 0-LCD hybrid-solver program. It is deliberately gated behind Phase 1c (#319) so the 4th hop is priced from the DB mirror, not LCD: the per-hop simulation cost is the whole reason the default cap was held at 3, and that cost goes away once optimization reads db_orderbook_sim instead of issuing live HybridSimulation LCD calls.

Current codebase

Hop caps live in indexer/src/api/route_solver.rs:

  • GET_DEFAULT_MAX_HOPS: usize = 3 (route_solver.rs:31) — the default hybrid-aware GET cap (ADR 0001 / #191).
  • GET_POOL_ONLY_MAX_HOPS: usize = 4 (route_solver.rs:33) — legacy pool-only GET (pool_only=true / hybrid_optimize=false), selected by get_pool_only_max_hops (route_solver.rs:374) and fed into resolve_route_with_max_hops at the GET handler (route_solver.rs:704-706).
  • On-chain router cap: MAX_HOPS: usize = 4 in smartcontracts/contracts/router/src/contract.rs:21, enforced at contract.rs:187, :476, :554. So 4 hops is already the executable ceiling; the indexer default is the only thing capped below it.

The hybrid GET solver consumes the cap in exactly one place:

  • solve_global_best_execution (indexer/src/api/best_execution.rs:115) calls enumerate_path_candidates(&state.pool, token_in, token_out, GET_DEFAULT_MAX_HOPS) (best_execution.rs:125), which hands max_hops to route_paths::find_paths_top_k(start, goal, &pair_rows, max_hops, MAX_PATH_CANDIDATES) (best_execution.rs:94-95). MAX_PATH_CANDIDATES = 5 (best_execution.rs:18).
  • The candidate loop (best_execution.rs:130-202) runs serially over up to 5 candidates; each candidate awaits optimize_multihop_hybrid_joint (best_execution.rs:142) then maybe_simulate (best_execution.rs:159). LCD accounting per candidate is estimate_lcd_calls(hop_count) (best_execution.rs:222-226), = hop_count * (17 + 2*17) — i.e. linear in hop count.

Budget constant that must move with the cap:

  • LCD_HYBRID_SIM_BUDGET = MAX_PATH_CANDIDATES * GET_DEFAULT_MAX_HOPS * (17 + 2 * 2 * 17) (best_execution.rs:26-27) — the documented worst-case pair-level HybridSimulation upper bound. Today that is 5 * 3 * 85 = 1275. Because it references GET_DEFAULT_MAX_HOPS directly, bumping the constant re-derives it to 5 * 4 * 85 = 1700 automatically — but the per-request cost grows ~33% and that needs to be acknowledged and bounded, not silently accepted. The budget_tests::lcd_budget_is_documented_constant test (best_execution.rs:33-36) only asserts > 0, so it will not catch a regression in the magnitude.

Path enumeration is already hardened against the extra hop (#286):

  • find_paths_top_k / find_paths_top_k_instrumented (indexer/src/api/route_paths.rs:74, :87) gate the DFS with a hop_distance_to_goal reachability map (route_paths.rs:48-67) so the search is O(V+E) and never expands an unreachable subtree — see unreachable_goal_does_not_explode style tests (route_paths.rs:362-409). The instrumented expansion count is what proves the 4th hop does not blow up enumeration on a dense graph.

Pool-only GET and POST already operate at 4 hops (route_solver.rs:363, :737), so this change brings the default hybrid GET path into line with the rest of the surface.

Why this is needed

  • The router executes up to 4 hops, but the default hybrid GET solver only ever enumerates 3. Pairs that are only connected via a 4-hop path get a hybrid quote of "no route within 3 hops" unless the caller knows to pass pool_only=true — and pool-only throws away the book legs, so even then the quote is worse than what the chain can do.
  • Phase 1c (#319) moves per-hop pricing off LCD onto the DB mirror (db_orderbook_sim). Once that lands, the 4th hop is essentially free per request, which removes the original reason the cap was pinned at 3. Plastic's call on #279: once the DB-priced change is in, then limit hops to 4.

Constraints and guardrails

  • Do this after #319 (Phase 1c) merges. If the cap goes to 4 while pricing is still LCD-backed, every hybrid GET pays an extra full grid + 2 coordinate passes per candidate (estimate_lcd_calls × up to 5 candidates), which is exactly the LCD load the bucketed cache was built to avoid. Don't ship this on LCD pricing.
  • Do not exceed 4. The router enforces MAX_HOPS = 4; a 5-hop indexer route would be un-executable and would just burn enumeration + sim budget.
  • Keep GET_DEFAULT_MAX_HOPS and GET_POOL_ONLY_MAX_HOPS as distinct named constants even though they become equal — they carry different intent (default hybrid vs legacy pool-only escape hatch) and a future change may diverge them again. Do not collapse them into one symbol.
  • No cache-key change. hybrid_cache_key (route_solver.rs:532) keys on solver_version | token_in | token_out | amount_bucket | max_maker_fills | trader | discount_tier; hop count is not and should not be a key component (the route is derived deterministically from token_in/out + the pair graph). Discount-tier keying is already correct per #283 (MR !751) — leave it alone.
  • MAX_PATH_CANDIDATES stays at 5. This issue changes hop depth only, not candidate breadth — candidate-budget work is #286's scope.
  1. After #319 lands, change GET_DEFAULT_MAX_HOPS to 4 at route_solver.rs:31 and update its doc comment + the module-level "max 3 hops" prose at route_solver.rs:3.
  2. Re-derive and re-document LCD_HYBRID_SIM_BUDGET (best_execution.rs:26-27). Since it now prices against the DB mirror rather than live LCD, also reconsider whether the constant's name/comment still reads as "LCD" worst-case or should be reframed as the DB-sim worst-case bound that #319 introduces. Either way, state the new numeric bound (5 * 4 * 85 = 1700) explicitly in the comment so reviewers see the per-request cost moved.
  3. Confirm enumerate_path_candidates and find_paths_top_k need no signature change — they already take max_hops as a parameter, so the bump propagates from the single constant. Verify nothing else in best_execution.rs hard-codes 3.
  4. Sanity-check the pool-only path still resolves at 4 (get_pool_only_max_hops, route_solver.rs:374) — now numerically identical to the default, which is the intended convergence.

Acceptance criteria

  • GET_DEFAULT_MAX_HOPS = 4 in route_solver.rs; module doc and the route_solver.rs:3 "max 3 hops" comment updated to 4.
  • A genuinely 4-hop-only token pair (no 3-hop shortcut) is discovered and returns a hybrid (or pool) quote via default GET amount_in=… — not just via pool_only=true.
  • LCD_HYBRID_SIM_BUDGET re-derived to the new bound and its doc comment updated to state the new magnitude and that pricing is DB-backed post-#319; the budget test asserts the actual expected value, not merely > 0.
  • find_paths_top_k reachability/enumeration behavior at max_hops = 4 is unchanged in spirit: an unreachable goal still produces zero expansions (no O(branching^4) blow-up), proven via the instrumented expansion count (#286 guarantees preserved).
  • No change to hybrid_cache_key shape or to discount-tier keying (#283 stays intact).
  • Indexer routing crate builds and existing route tests pass (api_route_solve.rs, route_paths.rs unit tests).

Test plan

  • Unit (indexer/src/api/route_paths.rs tests): add a 4-hop-only case modeled on deep_route_within_budget_is_found (route_paths.rs:490-500) — a linear 0-1-2-3-4 graph with no shortcut, assert find_paths_top_k(0, 4, &pairs, 4, 5) returns one 4-edge path, and that max_hops = 3 excludes it. Add an instrumented unreachable-goal assertion at max_hops = 4 to confirm bounded expansions.
  • Budget unit (best_execution.rs budget_tests): assert LCD_HYBRID_SIM_BUDGET == 5 * 4 * 85 after the bump so the magnitude is pinned and a future cap change forces a deliberate update.
  • API (indexer/tests/api_route_solve.rs): extend the existing route-solve coverage (the "3 hops" || "4 hops" assertion at api_route_solve.rs:73 already anticipates the 4-hop message) with a default-GET case over a seeded 4-hop graph asserting a quote is returned rather than no route.
  • Cargo: cargo test -p indexer route (or the indexer test target) green; no LCD calls required for the enumeration/budget tests since path discovery is graph-only.
## Summary Bump `GET_DEFAULT_MAX_HOPS` from 3 to 4 so the hybrid GET best-execution solver discovers and prices 4-hop routes, matching the pool-only escape hatch (`GET_POOL_ONLY_MAX_HOPS = 4`) and the on-chain router cap (`MAX_HOPS = 4`). Right now the default hybrid GET path is one hop short of what the router can actually execute, so any token pair whose only viable route is 4 hops is reachable via `pool_only=true` but never gets a hybrid (book + pool) split quote. This is Phase 2 of the #279 0-LCD hybrid-solver program. It is deliberately gated behind Phase 1c (#319) so the 4th hop is priced from the DB mirror, not LCD: the per-hop simulation cost is the whole reason the default cap was held at 3, and that cost goes away once optimization reads `db_orderbook_sim` instead of issuing live `HybridSimulation` LCD calls. ## Current codebase Hop caps live in `indexer/src/api/route_solver.rs`: - `GET_DEFAULT_MAX_HOPS: usize = 3` (`route_solver.rs:31`) — the default hybrid-aware GET cap (ADR 0001 / #191). - `GET_POOL_ONLY_MAX_HOPS: usize = 4` (`route_solver.rs:33`) — legacy pool-only GET (`pool_only=true` / `hybrid_optimize=false`), selected by `get_pool_only_max_hops` (`route_solver.rs:374`) and fed into `resolve_route_with_max_hops` at the GET handler (`route_solver.rs:704-706`). - On-chain router cap: `MAX_HOPS: usize = 4` in `smartcontracts/contracts/router/src/contract.rs:21`, enforced at `contract.rs:187`, `:476`, `:554`. So 4 hops is already the executable ceiling; the indexer default is the only thing capped below it. The hybrid GET solver consumes the cap in exactly one place: - `solve_global_best_execution` (`indexer/src/api/best_execution.rs:115`) calls `enumerate_path_candidates(&state.pool, token_in, token_out, GET_DEFAULT_MAX_HOPS)` (`best_execution.rs:125`), which hands `max_hops` to `route_paths::find_paths_top_k(start, goal, &pair_rows, max_hops, MAX_PATH_CANDIDATES)` (`best_execution.rs:94-95`). `MAX_PATH_CANDIDATES = 5` (`best_execution.rs:18`). - The candidate loop (`best_execution.rs:130-202`) runs serially over up to 5 candidates; each candidate awaits `optimize_multihop_hybrid_joint` (`best_execution.rs:142`) then `maybe_simulate` (`best_execution.rs:159`). LCD accounting per candidate is `estimate_lcd_calls(hop_count)` (`best_execution.rs:222-226`), `= hop_count * (17 + 2*17)` — i.e. linear in hop count. Budget constant that must move with the cap: - `LCD_HYBRID_SIM_BUDGET = MAX_PATH_CANDIDATES * GET_DEFAULT_MAX_HOPS * (17 + 2 * 2 * 17)` (`best_execution.rs:26-27`) — the documented worst-case pair-level `HybridSimulation` upper bound. Today that is `5 * 3 * 85 = 1275`. Because it references `GET_DEFAULT_MAX_HOPS` directly, bumping the constant re-derives it to `5 * 4 * 85 = 1700` automatically — but the per-request cost grows ~33% and that needs to be acknowledged and bounded, not silently accepted. The `budget_tests::lcd_budget_is_documented_constant` test (`best_execution.rs:33-36`) only asserts `> 0`, so it will not catch a regression in the magnitude. Path enumeration is already hardened against the extra hop (#286): - `find_paths_top_k` / `find_paths_top_k_instrumented` (`indexer/src/api/route_paths.rs:74`, `:87`) gate the DFS with a `hop_distance_to_goal` reachability map (`route_paths.rs:48-67`) so the search is O(V+E) and never expands an unreachable subtree — see `unreachable_goal_does_not_explode` style tests (`route_paths.rs:362-409`). The instrumented expansion count is what proves the 4th hop does not blow up enumeration on a dense graph. Pool-only GET and POST already operate at 4 hops (`route_solver.rs:363`, `:737`), so this change brings the default hybrid GET path into line with the rest of the surface. ## Why this is needed - The router executes up to 4 hops, but the default hybrid GET solver only ever enumerates 3. Pairs that are only connected via a 4-hop path get a hybrid quote of "no route within 3 hops" unless the caller knows to pass `pool_only=true` — and pool-only throws away the book legs, so even then the quote is worse than what the chain can do. - Phase 1c (#319) moves per-hop pricing off LCD onto the DB mirror (`db_orderbook_sim`). Once that lands, the 4th hop is essentially free per request, which removes the original reason the cap was pinned at 3. Plastic's call on #279: once the DB-priced change is in, then limit hops to 4. ## Constraints and guardrails - Do this **after** #319 (Phase 1c) merges. If the cap goes to 4 while pricing is still LCD-backed, every hybrid GET pays an extra full grid + 2 coordinate passes per candidate (`estimate_lcd_calls` × up to 5 candidates), which is exactly the LCD load the bucketed cache was built to avoid. Don't ship this on LCD pricing. - Do not exceed 4. The router enforces `MAX_HOPS = 4`; a 5-hop indexer route would be un-executable and would just burn enumeration + sim budget. - Keep `GET_DEFAULT_MAX_HOPS` and `GET_POOL_ONLY_MAX_HOPS` as distinct named constants even though they become equal — they carry different intent (default hybrid vs legacy pool-only escape hatch) and a future change may diverge them again. Do not collapse them into one symbol. - No cache-key change. `hybrid_cache_key` (`route_solver.rs:532`) keys on `solver_version | token_in | token_out | amount_bucket | max_maker_fills | trader | discount_tier`; hop count is not and should not be a key component (the route is derived deterministically from token_in/out + the pair graph). Discount-tier keying is already correct per #283 (MR !751) — leave it alone. - `MAX_PATH_CANDIDATES` stays at 5. This issue changes hop depth only, not candidate breadth — candidate-budget work is #286's scope. ## Recommended direction 1. After #319 lands, change `GET_DEFAULT_MAX_HOPS` to `4` at `route_solver.rs:31` and update its doc comment + the module-level "max 3 hops" prose at `route_solver.rs:3`. 2. Re-derive and re-document `LCD_HYBRID_SIM_BUDGET` (`best_execution.rs:26-27`). Since it now prices against the DB mirror rather than live LCD, also reconsider whether the constant's name/comment still reads as "LCD" worst-case or should be reframed as the DB-sim worst-case bound that #319 introduces. Either way, state the new numeric bound (`5 * 4 * 85 = 1700`) explicitly in the comment so reviewers see the per-request cost moved. 3. Confirm `enumerate_path_candidates` and `find_paths_top_k` need no signature change — they already take `max_hops` as a parameter, so the bump propagates from the single constant. Verify nothing else in `best_execution.rs` hard-codes `3`. 4. Sanity-check the pool-only path still resolves at 4 (`get_pool_only_max_hops`, `route_solver.rs:374`) — now numerically identical to the default, which is the intended convergence. ## Acceptance criteria - [ ] `GET_DEFAULT_MAX_HOPS = 4` in `route_solver.rs`; module doc and the `route_solver.rs:3` "max 3 hops" comment updated to 4. - [ ] A genuinely 4-hop-only token pair (no 3-hop shortcut) is discovered and returns a hybrid (or pool) quote via default GET `amount_in=…` — not just via `pool_only=true`. - [ ] `LCD_HYBRID_SIM_BUDGET` re-derived to the new bound and its doc comment updated to state the new magnitude and that pricing is DB-backed post-#319; the budget test asserts the actual expected value, not merely `> 0`. - [ ] `find_paths_top_k` reachability/enumeration behavior at `max_hops = 4` is unchanged in spirit: an unreachable goal still produces zero expansions (no O(branching^4) blow-up), proven via the instrumented expansion count (#286 guarantees preserved). - [ ] No change to `hybrid_cache_key` shape or to discount-tier keying (#283 stays intact). - [ ] Indexer routing crate builds and existing route tests pass (`api_route_solve.rs`, `route_paths.rs` unit tests). ## Test plan - Unit (`indexer/src/api/route_paths.rs` tests): add a 4-hop-only case modeled on `deep_route_within_budget_is_found` (`route_paths.rs:490-500`) — a linear `0-1-2-3-4` graph with no shortcut, assert `find_paths_top_k(0, 4, &pairs, 4, 5)` returns one 4-edge path, and that `max_hops = 3` excludes it. Add an instrumented unreachable-goal assertion at `max_hops = 4` to confirm bounded expansions. - Budget unit (`best_execution.rs` `budget_tests`): assert `LCD_HYBRID_SIM_BUDGET == 5 * 4 * 85` after the bump so the magnitude is pinned and a future cap change forces a deliberate update. - API (`indexer/tests/api_route_solve.rs`): extend the existing route-solve coverage (the `"3 hops" || "4 hops"` assertion at `api_route_solve.rs:73` already anticipates the 4-hop message) with a default-GET case over a seeded 4-hop graph asserting a quote is returned rather than `no route`. - Cargo: `cargo test -p indexer route` (or the indexer test target) green; no LCD calls required for the enumeration/budget tests since path discovery is graph-only. ## Related - Parent program: #279 (0-LCD hybrid solver) — https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/279 - Hard dependency: #319 (Phase 1c — `db_orderbook_sim` + rewire optimizer to read DB not LCD) — https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/319 — this must land first so the 4th hop is DB-priced. - #286 (route DFS path-candidate / enumeration budget) — https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/286 — reachability guarantees the 4-hop bump must not regress. - #283 (cache-key discount-tier correctness, SHIPPED MR !751) — https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/issues/283 — cache keying is out of scope here.
Brouie commented 2026-06-05 08:23:46 +00:00 (Migrated from gitlab.com)

mentioned in issue #279

mentioned in issue #279
Brouie commented 2026-06-05 08:23:47 +00:00 (Migrated from gitlab.com)

mentioned in issue #319

mentioned in issue #319
Brouie commented 2026-06-05 08:24:27 +00:00 (Migrated from gitlab.com)

marked as related to #319

marked as related to #319
ghost1 commented 2026-06-05 11:09:28 +00:00 (Migrated from gitlab.com)

mentioned in commit 0bc6390cec

mentioned in commit 0bc6390cecc9b1f7f5f2522cf26b7b8d06886f9a
PlasticDigits commented 2026-06-05 11:09:50 +00:00 (Migrated from gitlab.com)

mentioned in merge request !796

mentioned in merge request !796
PlasticDigits commented 2026-06-05 11:10:01 +00:00 (Migrated from gitlab.com)

Implementation complete — MR !796.

What changed

  • GET_DEFAULT_MAX_HOPS raised 3 → 4 (route_solver.rs)
  • LCD_HYBRID_SIM_BUDGET now 1700 (5×4×85); unit test pins exact value
  • New 4-hop path enumeration tests + default-GET API regression (seed_route_solve_4hop)
  • Docs + check_route_solver_docs.py updated

Acceptance results

Criterion Result How verified
GET_DEFAULT_MAX_HOPS = 4 + docs PASS code + doc diff
4-hop-only pair via default GET PASS (unit) / SKIP (integration) four_hop_only_route_within_budget_is_found; route_solve_get_default_hybrid_four_hops added — needs Postgres
LCD_HYBRID_SIM_BUDGET = 1700 + pinned test PASS cargo test --lib lcd_budget_is_documented_constant
Reachability at max_hops=4 PASS unreachable_goal_at_four_hops_does_zero_enumeration
No cache-key change PASS diff review
Route tests green PASS (lib) / SKIP (integration) cargo test --lib route_paths::tests; no Postgres on agent VM

Blocker for merge

#319 (Phase 1c / db_orderbook_sim) is not on main yet. Per issue constraints, merge !796 only after #319 lands so the 4th hop is DB-priced rather than LCD-backed.

Issue left open pending #319 + CI/integration verification on Postgres.

Implementation complete — MR [!796](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/78). ### What changed - `GET_DEFAULT_MAX_HOPS` raised **3 → 4** (`route_solver.rs`) - `LCD_HYBRID_SIM_BUDGET` now **1700** (`5×4×85`); unit test pins exact value - New 4-hop path enumeration tests + default-GET API regression (`seed_route_solve_4hop`) - Docs + `check_route_solver_docs.py` updated ### Acceptance results | Criterion | Result | How verified | |-----------|--------|--------------| | `GET_DEFAULT_MAX_HOPS = 4` + docs | **PASS** | code + doc diff | | 4-hop-only pair via default GET | **PASS** (unit) / **SKIP** (integration) | `four_hop_only_route_within_budget_is_found`; `route_solve_get_default_hybrid_four_hops` added — needs Postgres | | `LCD_HYBRID_SIM_BUDGET = 1700` + pinned test | **PASS** | `cargo test --lib lcd_budget_is_documented_constant` | | Reachability at max_hops=4 | **PASS** | `unreachable_goal_at_four_hops_does_zero_enumeration` | | No cache-key change | **PASS** | diff review | | Route tests green | **PASS** (lib) / **SKIP** (integration) | `cargo test --lib route_paths::tests`; no Postgres on agent VM | ### Blocker for merge **#319** (Phase 1c / `db_orderbook_sim`) is not on `main` yet. Per issue constraints, merge !796 only after #319 lands so the 4th hop is DB-priced rather than LCD-backed. Issue left **open** pending #319 + CI/integration verification on Postgres.
PlasticDigits commented 2026-06-05 12:30:15 +00:00 (Migrated from gitlab.com)

mentioned in commit 7f2f716ac3

mentioned in commit 7f2f716ac338a0f337ff5535a40f7c05f49a9f69
ghost1 commented 2026-06-05 12:42:39 +00:00 (Migrated from gitlab.com)

mentioned in commit e0f9e00ca2

mentioned in commit e0f9e00ca2d570b80eb9b8510698f15d42e14efa
ghost1 commented 2026-06-05 12:43:27 +00:00 (Migrated from gitlab.com)

mentioned in commit 0583223a6a

mentioned in commit 0583223a6af69ed46903d25ed5336eb9644b98dd
PlasticDigits commented 2026-06-05 12:44:28 +00:00 (Migrated from gitlab.com)

mentioned in merge request !797

mentioned in merge request !797
PlasticDigits commented 2026-06-05 12:44:29 +00:00 (Migrated from gitlab.com)

mentioned in merge request !798

mentioned in merge request !798
PlasticDigits commented 2026-06-05 13:38:50 +00:00 (Migrated from gitlab.com)

mentioned in merge request !808

mentioned in merge request !808
ghost1 commented 2026-06-05 13:38:57 +00:00 (Migrated from gitlab.com)

mentioned in commit 666d7f4c4b

mentioned in commit 666d7f4c4bd7403d3b10f6195c3eed78e8e4faab
PlasticDigits commented 2026-06-05 13:38:59 +00:00 (Migrated from gitlab.com)

Verification complete — #323

Implementation from !796 is on main. Dependency #319 (DB mirror pricing) is also merged.

Acceptance results

Criterion Result How verified
GET_DEFAULT_MAX_HOPS = 4 + module docs PASS route_solver.rs:31 = 4; module doc line 3 updated
4-hop-only pair via default GET PASS cargo test --test api_route_solve route_solve_get_default_hybrid_four_hops
LCD_HYBRID_SIM_BUDGET = 1700 + pinned test PASS cargo test --lib lcd_budget_is_documented_constant
Reachability at max_hops = 4 PASS four_hop_only_route_within_budget_is_found, unreachable_goal_at_four_hops_does_zero_enumeration
No hybrid_cache_key change PASS Code review — key shape unchanged (#283 intact)
Route tests green PASS cargo test --test api_route_solve (23/23), cargo test --lib route_paths (12/12)
Docs drift guard PASS (after fix) python3 scripts/check_route_solver_docs.py — was failing on SOLVER_VERSION rename from #319

Docs drift fix

Verification found stale 3-hop references and a broken drift guard (SOLVER_VERSION → SOLVER_VERSION_LCD / SOLVER_VERSION_DB). Fixed in !808.

Issue left open pending MR !808 merge.

## Verification complete — [#323](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/323) Implementation from [!796](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/78) is on `main`. Dependency [#319](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/319) (DB mirror pricing) is also merged. ### Acceptance results | Criterion | Result | How verified | |-----------|--------|--------------| | `GET_DEFAULT_MAX_HOPS = 4` + module docs | **PASS** | `route_solver.rs:31` = 4; module doc line 3 updated | | 4-hop-only pair via default GET | **PASS** | `cargo test --test api_route_solve route_solve_get_default_hybrid_four_hops` | | `LCD_HYBRID_SIM_BUDGET = 1700` + pinned test | **PASS** | `cargo test --lib lcd_budget_is_documented_constant` | | Reachability at `max_hops = 4` | **PASS** | `four_hop_only_route_within_budget_is_found`, `unreachable_goal_at_four_hops_does_zero_enumeration` | | No `hybrid_cache_key` change | **PASS** | Code review — key shape unchanged (#283 intact) | | Route tests green | **PASS** | `cargo test --test api_route_solve` (23/23), `cargo test --lib route_paths` (12/12) | | Docs drift guard | **PASS** (after fix) | `python3 scripts/check_route_solver_docs.py` — was failing on `SOLVER_VERSION` rename from #319 | ### Docs drift fix Verification found stale 3-hop references and a broken drift guard (`SOLVER_VERSION` → `SOLVER_VERSION_LCD` / `SOLVER_VERSION_DB`). Fixed in [!808](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/90). Issue left **open** pending MR !808 merge.
PlasticDigits commented 2026-06-05 13:43:58 +00:00 (Migrated from gitlab.com)

mentioned in commit e41f61bb11

mentioned in commit e41f61bb11ba2175c304bbc3bd917aede0b83008
Brouie commented 2026-06-06 01:19:51 +00:00 (Migrated from gitlab.com)

#323 verified — checked on current main (the merged #323 commits 0bc6390 + the 666d7f4 doc cleanup). Pure indexer route-solver, so this is source + unit + the Postgres-backed integration tests; no chain redeploy needed. I ran the integration case the cloud agent had to skip (no Postgres on its side), and it's green.

Acceptance criteria, each mapped to what actually ran:

  • GET_DEFAULT_MAX_HOPS = 4 + docs: route_solver.rs:31 is = 4; the module doc (route_solver.rs:3-6) now reads "max 4 hops" (the old "max 3 hops" prose is gone), and docs/route-solver.md + ADR 0002 carry the 3->4 note.
  • 4-hop-only pair on default GET: route_solve_get_default_hybrid_four_hops passes against a real A->B->C->D->E seed with no 3-hop shortcut (seed_route_solve_4hop) — quote returned via default amount_in GET, not pool_only. The one the agent skipped, now green.
  • LCD_HYBRID_SIM_BUDGET re-derived + comment: best_execution.rs:36-41 states DB-mirror pricing post-#319 and "5 x 4 x 85 = 1700"; lcd_budget_is_documented_constant asserts == 5485 (not just > 0).
  • reachability at 4 hops / no blow-up: unreachable_goal_at_four_hops_does_zero_enumeration + dense_unreachable_graph_does_zero_enumeration assert zero instrumented expansions; four_hop_only_route_within_budget_is_found covers the reachable 4-hop case.
  • no hybrid_cache_key change / #283 intact: #323's commit 0bc6390 touches zero cache-key lines (checked the diff); #283 tier isolation still green (route_solve_get_cache_tier_isolation).
  • crate builds + route tests pass: api_route_solve 23/23, api_route_solve_db_hybrid 3/3, route_paths unit all green; full lib suite 131/0; make lint clean.

All six hold. @PlasticDigits — over to you for the verify-agent + close. (Phase map for #279: 1a done, 1b #322, 1c #319 merged, 2 = this, 3 = #324.)

#323 verified — checked on current main (the merged #323 commits 0bc6390 + the 666d7f4 doc cleanup). Pure indexer route-solver, so this is source + unit + the Postgres-backed integration tests; no chain redeploy needed. I ran the integration case the cloud agent had to skip (no Postgres on its side), and it's green. Acceptance criteria, each mapped to what actually ran: - GET_DEFAULT_MAX_HOPS = 4 + docs: route_solver.rs:31 is `= 4`; the module doc (route_solver.rs:3-6) now reads "max 4 hops" (the old "max 3 hops" prose is gone), and docs/route-solver.md + ADR 0002 carry the 3->4 note. - 4-hop-only pair on default GET: route_solve_get_default_hybrid_four_hops passes against a real A->B->C->D->E seed with no 3-hop shortcut (seed_route_solve_4hop) — quote returned via default amount_in GET, not pool_only. The one the agent skipped, now green. - LCD_HYBRID_SIM_BUDGET re-derived + comment: best_execution.rs:36-41 states DB-mirror pricing post-#319 and "5 x 4 x 85 = 1700"; lcd_budget_is_documented_constant asserts == 5*4*85 (not just > 0). - reachability at 4 hops / no blow-up: unreachable_goal_at_four_hops_does_zero_enumeration + dense_unreachable_graph_does_zero_enumeration assert zero instrumented expansions; four_hop_only_route_within_budget_is_found covers the reachable 4-hop case. - no hybrid_cache_key change / #283 intact: #323's commit 0bc6390 touches zero cache-key lines (checked the diff); #283 tier isolation still green (route_solve_get_cache_tier_isolation). - crate builds + route tests pass: api_route_solve 23/23, api_route_solve_db_hybrid 3/3, route_paths unit all green; full lib suite 131/0; make lint clean. All six hold. @PlasticDigits — over to you for the verify-agent + close. (Phase map for #279: 1a done, 1b #322, 1c #319 merged, 2 = this, 3 = #324.)
PlasticDigits commented 2026-06-06 07:00:01 +00:00 (Migrated from gitlab.com)

Verification complete — #323

Independent re-verification on branch main (2026-06-06). Implementation from !796 + doc cleanup !808. Dependency #319 (DB mirror pricing) is merged on main.

Acceptance results

Criterion Result How verified
GET_DEFAULT_MAX_HOPS = 4 + module docs PASS route_solver.rs:31 = 4; module doc lines 3–6 read "max 4 hops"
4-hop-only pair via default GET PASS cargo test --test api_route_solve route_solve_get_default_hybrid_four_hops — quote via default amount_in GET (not pool_only), 4 hops with hybrid ops
LCD_HYBRID_SIM_BUDGET = 1700 + pinned test PASS best_execution.rs:36-41 documents DB-mirror pricing post-#319 and 5 × 4 × 85 = 1700; cargo test --lib lcd_budget_is_documented_constant asserts == 5*4*85
Reachability at max_hops = 4 PASS cargo test --lib route_paths::tests — four_hop_only_route_within_budget_is_found, unreachable_goal_at_four_hops_does_zero_enumeration (0 expansions)
No hybrid_cache_key change / #283 intact PASS cargo test --lib hybrid_cache_key (4/4); key shape solver_version|token_in|token_out|amount_bucket|mmf|d{tier} unchanged
Route tests green PASS cargo test --test api_route_solve (23/23), cargo test --test api_route_solve_db_hybrid (3/3), cargo test --lib route_paths::tests (12/12)
Docs drift guard PASS python3 scripts/check_route_solver_docs.py — OK

Commands run

make setup-indexer-postgres
cargo test --lib lcd_budget_is_documented_constant
cargo test --lib route_paths::tests
cargo test --lib hybrid_cache_key
cargo test --test api_route_solve -- --test-threads=1
cargo test --test api_route_solve_db_hybrid -- --test-threads=1
python3 scripts/check_route_solver_docs.py

All six acceptance criteria hold. Closing as verified.

## Verification complete — [#323](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/323) Independent re-verification on branch `main` (2026-06-06). Implementation from [!796](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/78) + doc cleanup [!808](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/90). Dependency [#319](https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/319) (DB mirror pricing) is merged on `main`. ### Acceptance results | Criterion | Result | How verified | |-----------|--------|--------------| | `GET_DEFAULT_MAX_HOPS = 4` + module docs | **PASS** | `route_solver.rs:31` = 4; module doc lines 3–6 read "max **4 hops**" | | 4-hop-only pair via default GET | **PASS** | `cargo test --test api_route_solve route_solve_get_default_hybrid_four_hops` — quote via default `amount_in` GET (not `pool_only`), 4 hops with hybrid ops | | `LCD_HYBRID_SIM_BUDGET = 1700` + pinned test | **PASS** | `best_execution.rs:36-41` documents DB-mirror pricing post-#319 and `5 × 4 × 85 = 1700`; `cargo test --lib lcd_budget_is_documented_constant` asserts `== 5*4*85` | | Reachability at `max_hops = 4` | **PASS** | `cargo test --lib route_paths::tests` — `four_hop_only_route_within_budget_is_found`, `unreachable_goal_at_four_hops_does_zero_enumeration` (0 expansions) | | No `hybrid_cache_key` change / #283 intact | **PASS** | `cargo test --lib hybrid_cache_key` (4/4); key shape `solver_version\|token_in\|token_out\|amount_bucket\|mmf\|d{tier}` unchanged | | Route tests green | **PASS** | `cargo test --test api_route_solve` (23/23), `cargo test --test api_route_solve_db_hybrid` (3/3), `cargo test --lib route_paths::tests` (12/12) | | Docs drift guard | **PASS** | `python3 scripts/check_route_solver_docs.py` — OK | ### Commands run ```bash make setup-indexer-postgres cargo test --lib lcd_budget_is_documented_constant cargo test --lib route_paths::tests cargo test --lib hybrid_cache_key cargo test --test api_route_solve -- --test-threads=1 cargo test --test api_route_solve_db_hybrid -- --test-threads=1 python3 scripts/check_route_solver_docs.py ``` All six acceptance criteria hold. Closing as verified.
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-06-06 07:00:06 +00:00
PlasticDigits commented 2026-06-08 08:43:13 +00:00 (Migrated from gitlab.com)

mentioned in commit 88b50f1519

mentioned in commit 88b50f1519abe021d3a8496485daf3c3e8ddc80f
PlasticDigits commented 2026-06-08 08:43:13 +00:00 (Migrated from gitlab.com)

mentioned in commit 17b9bba754

mentioned in commit 17b9bba75477abcfd828b895c692fe7bbbe548f3
PlasticDigits commented 2026-07-13 10:33:13 +00:00 (Migrated from gitlab.com)

mentioned in issue #485

mentioned in issue #485
PlasticDigits commented 2026-08-27 11:52:21 +00:00 (Migrated from gitlab.com)

mentioned in issue #690

mentioned in issue #690
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
code/cl8y-dex-terraclassic#323
No description provided.