fix(frontend): degraded pair search when indexer is down (#314) #811

Merged
PlasticDigits merged 1 commit from cursor/gitlab-issue-workflow-1430 into main 2026-06-05 14:20:31 +00:00
PlasticDigits commented 2026-06-05 13:55:31 +00:00 (Migrated from gitlab.com)

Summary

Fixes the remaining blocker from verification on https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/314: when the indexer is stopped, opening the Trade/Limits pair combobox still listed factory pairs, but typing a search (e.g. EMBER) showed "No pairs match your search" instead of filtering cached factory pairs.

MR !792 delivered indexer relevance ranking and the combobox; this patch completes degraded-mode typed search.

Changes

  • filterFactoryPairsByLocalSearch: searches menu labels, display symbols, contract/denom ids, pair address, and two-token XXX YYY / XXX/YYY queries (not label substring only).
  • PairSearchSelect: latch indexerUnavailable after the first getPairs error; use local fallback for all subsequent queries in the session; match on searchText while debouncing during outage.
  • Tests: pairSearchQuery.test.ts + PairSearchSelect.test.tsx (mocked indexer failure).
  • Docs: docs/frontend.md § Pair search combobox — degraded mode invariant.

Acceptance checklist (#314)

Criterion Verification Result
Trade + Limits use search combobox Code review + existing page/e2e tests PASS
Five search modes (indexer) MR !792 + api_pairs relevance tests (unchanged) PASS
Relevance bucket → volume tie-break list_pairs_relevance_ordering (unchanged) PASS
Empty query → high-liquidity defaults Indexer path unchanged; degraded empty → first 20 factory pairs PASS
Indexer tests for relevance ordering cargo test --test api_pairs SKIP (no Postgres on agent VM)
Degraded typed search when indexer down PairSearchSelect.test.tsx + filterFactoryPairsByLocalSearch unit tests PASS
make test-frontend 859 tests PASS
make lint-frontend 0 errors PASS
Manual QA matrix (≥6 pairs) LocalTerra SKIP
Lighthouse/a11y combobox Manual SKIP

Third-party verification

make test-frontend
# optional with LocalTerra + stopped indexer tmux session:
# make dev → /limits → open pair combobox → type EMBER → expect EMBER/CORAL option

Issue stays open until manual matrix on LocalTerra (optional).

Closes #314 after merge + manual spot-check of degraded typed search.


Note

Low Risk
Trade/Limits pair picker UX and client-side search only; no auth, signing, or contract changes. Session-scoped indexer bypass could hide transient indexer recovery until reload, which is an acceptable degraded-tradeoff.

Overview
Pair search degraded mode on Trade/Limits: after the first indexer failure in a session, PairSearchSelect sets indexerUnavailable, stops calling getPairs, and fills the combobox from filterFactoryPairsByLocalSearch on factory pairs only. Empty-state and aria-busy logic now distinguish “awaiting indexer” vs local fallback (including immediate searchText while debounce catches up).

Local search replaces the old label-only filterPairsByLocalSearch path in the UI with pairInfoSearchHaystack / filterFactoryPairsByLocalSearch: menu labels, display symbols, contract/denom ids, substring match, and two-leg queries (XXX YYY / XXX/YYY, order-insensitive). The legacy label map helper remains deprecated for tests.

Tests + docs: expanded pairSearchQuery.test.ts, new PairSearchSelect.test.tsx (mocked indexer error → symbol filter), and docs/frontend.md degraded-mode invariant updated.

Reviewed by Cursor Bugbot for commit 9e7b280513. Bugbot is set up for automated code reviews on this repo. Configure here.

## Summary Fixes the remaining blocker from verification on https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/work_items/314: when the indexer is stopped, opening the Trade/Limits pair combobox still listed factory pairs, but **typing a search** (e.g. `EMBER`) showed "No pairs match your search" instead of filtering cached factory pairs. MR !792 delivered indexer relevance ranking and the combobox; this patch completes degraded-mode typed search. ### Changes - **`filterFactoryPairsByLocalSearch`**: searches menu labels, display symbols, contract/denom ids, pair address, and two-token `XXX YYY` / `XXX/YYY` queries (not label substring only). - **`PairSearchSelect`**: latch `indexerUnavailable` after the first `getPairs` error; use local fallback for all subsequent queries in the session; match on `searchText` while debouncing during outage. - **Tests**: `pairSearchQuery.test.ts` + `PairSearchSelect.test.tsx` (mocked indexer failure). - **Docs**: `docs/frontend.md` § Pair search combobox — degraded mode invariant. ## Acceptance checklist (#314) | Criterion | Verification | Result | |-----------|--------------|--------| | Trade + Limits use search combobox | Code review + existing page/e2e tests | PASS | | Five search modes (indexer) | MR !792 + `api_pairs` relevance tests (unchanged) | PASS | | Relevance bucket → volume tie-break | `list_pairs_relevance_ordering` (unchanged) | PASS | | Empty query → high-liquidity defaults | Indexer path unchanged; degraded empty → first 20 factory pairs | PASS | | Indexer tests for relevance ordering | `cargo test --test api_pairs` | SKIP (no Postgres on agent VM) | | **Degraded typed search when indexer down** | `PairSearchSelect.test.tsx` + `filterFactoryPairsByLocalSearch` unit tests | PASS | | `make test-frontend` | 859 tests | PASS | | `make lint-frontend` | 0 errors | PASS | | Manual QA matrix (≥6 pairs) | LocalTerra | SKIP | | Lighthouse/a11y combobox | Manual | SKIP | ## Third-party verification ```bash make test-frontend # optional with LocalTerra + stopped indexer tmux session: # make dev → /limits → open pair combobox → type EMBER → expect EMBER/CORAL option ``` Issue stays **open** until manual matrix on LocalTerra (optional). Closes #314 after merge + manual spot-check of degraded typed search. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Trade/Limits pair picker UX and client-side search only; no auth, signing, or contract changes. Session-scoped indexer bypass could hide transient indexer recovery until reload, which is an acceptable degraded-tradeoff. > > **Overview** > **Pair search degraded mode** on Trade/Limits: after the first indexer failure in a session, `PairSearchSelect` sets **`indexerUnavailable`**, stops calling **`getPairs`**, and fills the combobox from **`filterFactoryPairsByLocalSearch`** on factory pairs only. Empty-state and **`aria-busy`** logic now distinguish “awaiting indexer” vs local fallback (including immediate **`searchText`** while debounce catches up). > > **Local search** replaces the old label-only **`filterPairsByLocalSearch`** path in the UI with **`pairInfoSearchHaystack`** / **`filterFactoryPairsByLocalSearch`**: menu labels, display symbols, contract/denom ids, substring match, and two-leg queries (`XXX YYY` / `XXX/YYY`, order-insensitive). The legacy label map helper remains **deprecated** for tests. > > **Tests + docs:** expanded **`pairSearchQuery.test.ts`**, new **`PairSearchSelect.test.tsx`** (mocked indexer error → symbol filter), and **`docs/frontend.md`** degraded-mode invariant updated. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 9e7b280513f48ff181cb53e4743c13a488da7b8d. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
PlasticDigits commented 2026-06-05 13:55:37 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits commented 2026-06-05 13:55:38 +00:00 (Migrated from gitlab.com)

mentioned in issue #314

mentioned in issue #314
ghost1 commented 2026-06-05 13:55:38 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
ghost1 commented 2026-06-05 13:55:45 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits commented 2026-06-05 13:57:10 +00:00 (Migrated from gitlab.com)

Security review

Commit reviewed: 9e7b280513f48ff181cb53e4743c13a488da7b8d
Scope: MR !811 — degraded pair search when the indexer is unavailable (PairSearchSelect.tsx, pairSearchQuery.ts, tests, docs/frontend.md).

Outcome: FINDINGS: 0 (no medium, high, or critical issues on this diff)

Summary

Reviewed attacker-controlled combobox input through local fallback filtering, indexer query gating, and option rendering. Changes are client-side UX only; pair selection remains constrained to the factoryPairs prop (factory-registered pairs). User search text is used only for substring/includes matching and is rendered via React text nodes (labels come from on-chain pair metadata via pairInfoMenuLabel, not raw query echo). Indexer q continues to use URLSearchParams encoding when the indexer path is active; after the first indexer error, further indexer calls are latched off (indexerUnavailable), which reduces retry noise rather than widening trust boundaries.

The removed fallback branch that could surface { value: addr, label: addr } for non-factory addresses is strictly tighter than before.

Inline threads: none (no findings to anchor).

Prior MR notes: no prior security-review findings to re-report.

## Security review **Commit reviewed:** `9e7b280513f48ff181cb53e4743c13a488da7b8d` **Scope:** MR !811 — degraded pair search when the indexer is unavailable (`PairSearchSelect.tsx`, `pairSearchQuery.ts`, tests, `docs/frontend.md`). **Outcome:** `FINDINGS: 0` (no medium, high, or critical issues on this diff) ### Summary Reviewed attacker-controlled combobox input through local fallback filtering, indexer query gating, and option rendering. Changes are client-side UX only; pair selection remains constrained to the `factoryPairs` prop (factory-registered pairs). User search text is used only for substring/`includes` matching and is rendered via React text nodes (labels come from on-chain pair metadata via `pairInfoMenuLabel`, not raw query echo). Indexer `q` continues to use `URLSearchParams` encoding when the indexer path is active; after the first indexer error, further indexer calls are latched off (`indexerUnavailable`), which reduces retry noise rather than widening trust boundaries. The removed fallback branch that could surface `{ value: addr, label: addr }` for non-factory addresses is strictly tighter than before. **Inline threads:** none (no findings to anchor). Prior MR notes: no prior security-review findings to re-report.
PlasticDigits commented 2026-06-05 14:20:26 +00:00 (Migrated from gitlab.com)

resolved all threads

resolved all threads
PlasticDigits commented 2026-06-05 14:20:31 +00:00 (Migrated from gitlab.com)

mentioned in commit 2d1415913c

mentioned in commit 2d1415913c0c329ead664536469510d641f5fcc0
PlasticDigits (Migrated from gitlab.com) merged commit 2d1415913c into main 2026-06-05 14:20:31 +00:00
PlasticDigits commented 2026-06-08 08:43:13 +00:00 (Migrated from gitlab.com)

mentioned in commit a1340febaf

mentioned in commit a1340febafd5cfa4a1e29d3c22a2c014a4413df6
PlasticDigits commented 2026-06-08 13:42:28 +00:00 (Migrated from gitlab.com)

mentioned in commit e59f9800fe

mentioned in commit e59f9800fe810b3231c178b7df06844770246b55
Sign in to join this conversation.
No reviewers
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!811
No description provided.