Fix pair search degraded typed search + seed token names for QA relevance tier 2 (GitLab #314 follow-up) #328

Closed
opened 2026-06-05 13:44:11 +00:00 by PlasticDigits · 13 comments
PlasticDigits commented 2026-06-05 13:44:11 +00:00 (Migrated from gitlab.com)

Parent

Follow-ups to GitLab #314 (pair search combobox — open, MR !792 merged). Verification report (2026-06-05) identified two remaining gaps before closing #314.

Current codebase

Pair search combobox (shipped)

  • Frontend: PairSearchSelect (frontend-dapp/src/components/trade/PairSearchSelect.tsx) on Trade and Limit Orders pages. Debounced indexer GET /api/v1/pairs?q=&sort=relevance when combobox is open; factory pair set gates results.
  • Degraded mode (partial): When pairsQuery.isError, empty-query fallback lists up to 20 factory pairs via filterPairsByLocalSearch (frontend-dapp/src/utils/pairSearchQuery.ts). Typed search while indexer is down returns zero options — options memo builds from fallbackAddresses only when isError, but showEmptyState fires because debouncedSearch is non-empty and result stays [] (verification FAIL in #314 comment).
  • Indexer relevance: indexer/src/db/queries/pairs.rs tiers 1–5; tier 2 = token name substring (a0.name ILIKE / a1.name ILIKE). Covered by indexer/tests/api_pairs.rs::list_pairs_relevance_ordering with seeded Luna Classic name.
  • QA deploy tokens: scripts/deploy-dex-local.sh Phase 2 instantiates CW20 tokens with name and symbol in the instantiate msg (TOKEN_NAMES = Ember, Coral, …). Indexer may still show name='' if assets are not re-indexed with token metadata from chain — verification noted all QA assets had empty name in indexer DB after deploy.

Why this is needed

  1. Degraded typed search: When the indexer is unavailable, users typing EMBER or a pair symbol see "No pairs match your search" despite cached factory labels containing those strings. Empty-query fallback works; typed fallback does not — inconsistent outage UX and blocks closing #314.
  2. Token name tier QA: Manual relevance matrix cannot exercise tier 2 (name substring) on LocalTerra without indexer assets.name populated. Automated indexer test uses synthetic seed data; deploy QA stack should mirror production metadata for agent/human QA.

Constraints / guardrails

  • Reuse filterPairsByLocalSearch — do not fetch all pairs from chain on outage.
  • Factory gate: degraded results must still be factorySet.has(addr).
  • Preserve indexer-first path when healthy; degraded is only on pairsQuery.isError (not loading).
  • Selected pair prepend behavior unchanged (current value stays visible during non-matching search).
  • Token name seeding: use CW20 instantiate name field already present; ensure indexer ingests token metadata (factory/token discovery path) — do not hard-code names only in frontend.
  • PAIR_SEARCH_MIN_CHARS (2) and debounce (300ms) unchanged.
  • No new indexer API surface required for degraded mode.

Relevant files

Area Path
Combobox frontend-dapp/src/components/trade/PairSearchSelect.tsx — options memo, fallbackAddresses, showEmptyState
Local filter frontend-dapp/src/utils/pairSearchQuery.ts
Unit tests frontend-dapp/src/utils/__tests__/pairSearchQuery.test.ts
Component tests New: PairSearchSelect degraded-mode test (mock indexer error)
Deploy seed scripts/deploy-dex-local.sh — Phase 2 token instantiate, indexer bootstrap
Indexer assets indexer/src/indexer/parser.rs / token discovery — ensure name persisted
Relevance SQL indexer/src/db/queries/pairs.rs
Indexer test indexer/tests/api_pairs.rs
Docs docs/frontend.md § Pair search combobox invariants
  1. In PairSearchSelect options memo: when pairsQuery.isError and debouncedSearch is non-empty, populate result from filterPairsByLocalSearch(labelsByAddress, debouncedSearch, PAIR_SEARCH_RESULT_LIMIT) filtered by factorySet (same as fallbackAddresses logic — ensure fallbackAddresses is used or merge paths).
  2. Add subtle degraded indicator (optional): aria-busy off, dim "Offline search" hint — align with AGENTS_FRONTEND_MARKET_DATA_OUTAGE.md copy patterns; no env URLs.
  3. Unit/component test: mock getPairs rejection → type emb → options include Ember/Coral factory pairs.

B. Seed token names on LocalTerra QA deploy

  1. Confirm deploy instantiate msgs set distinct name values (already TOKEN_NAMES).
  2. Trace why indexer shows name='' post-deploy — fix asset upsert from CW20 token info query if metadata is dropped.
  3. Add deploy verification step or scripts/qa/ check: GET /api/v1/pairs?q=ember&sort=relevance returns tier-2/3 hits after indexer sync.
  4. Document in scripts/qa/README.md manual matrix row for token name search.

Acceptance criteria

  • Indexer stopped + typed query EMBER in Trade/Limits combobox returns matching factory pairs (not empty state).
  • Indexer healthy path unchanged (no local filter when API succeeds).
  • Empty query degraded mode still lists top factory pairs.
  • After make deploy-local + indexer sync, q=Ember (name substring) returns relevant pairs in live API test.
  • Frontend + indexer tests added/updated.
  • #314 can close after manual QA matrix re-run.

Test plan — all paths

Path Expected
Indexer up, typed search Indexer relevance results
Indexer up, empty query volume_24h desc default list
Indexer down, empty query Up to 20 factory pairs from labels
Indexer down, typed EMBER Local substring matches
Indexer down, typed zzzzz "No pairs match your search"
Indexer down, terra1… address Local label/addr match if in factory set
Selected pair + non-matching query Current selection prepended
Post-deploy API q=Ember Tier 2/3 hit with non-empty assets.name

Test plan — attack / abuse / hack vectors

Vector Expected
Indexer SSRF / error injection Client only filters local factory labels — no arbitrary URL fetch
Oversized q (>128) Indexer rejects when up; local filter truncates/ignores per PAIR_LIST_Q_MAX_LEN when down
Factory set bypass via degraded search Results always filtered factorySet.has(addr)
Unicode / case homoglyph in local filter toLowerCase + includes — no crash; bounded result count

Verification criteria

  • make test-frontend green (new degraded-mode test).
  • Manual: stop indexer tmux session → /limits → type EMBER → options appear.
  • curl '/api/v1/pairs?q=Ember&sort=relevance' on LocalTerra returns hits with populated token names.
  • Re-run #314 verification matrix (≥6 pairs) — no FAIL on degraded typed search or tier 2.
## Parent Follow-ups to GitLab **#314** (pair search combobox — **open**, MR !792 merged). Verification report (2026-06-05) identified two remaining gaps before closing #314. ## Current codebase ### Pair search combobox (shipped) - **Frontend:** `PairSearchSelect` (`frontend-dapp/src/components/trade/PairSearchSelect.tsx`) on Trade and Limit Orders pages. Debounced indexer `GET /api/v1/pairs?q=&sort=relevance` when combobox is open; factory pair set gates results. - **Degraded mode (partial):** When `pairsQuery.isError`, empty-query fallback lists up to 20 factory pairs via `filterPairsByLocalSearch` (`frontend-dapp/src/utils/pairSearchQuery.ts`). **Typed search while indexer is down returns zero options** — `options` memo builds from `fallbackAddresses` only when `isError`, but `showEmptyState` fires because `debouncedSearch` is non-empty and `result` stays `[]` (verification FAIL in #314 comment). - **Indexer relevance:** `indexer/src/db/queries/pairs.rs` tiers 1–5; **tier 2** = token **name** substring (`a0.name ILIKE` / `a1.name ILIKE`). Covered by `indexer/tests/api_pairs.rs::list_pairs_relevance_ordering` with seeded `Luna Classic` name. - **QA deploy tokens:** `scripts/deploy-dex-local.sh` Phase 2 instantiates CW20 tokens with `name` and `symbol` in the instantiate msg (`TOKEN_NAMES` = Ember, Coral, …). Indexer may still show `name=''` if assets are not re-indexed with token metadata from chain — verification noted all QA assets had empty `name` in indexer DB after deploy. ## Why this is needed 1. **Degraded typed search:** When the indexer is unavailable, users typing `EMBER` or a pair symbol see "No pairs match your search" despite cached factory labels containing those strings. Empty-query fallback works; typed fallback does not — inconsistent outage UX and blocks closing #314. 2. **Token name tier QA:** Manual relevance matrix cannot exercise **tier 2** (name substring) on LocalTerra without indexer `assets.name` populated. Automated indexer test uses synthetic seed data; deploy QA stack should mirror production metadata for agent/human QA. ## Constraints / guardrails - Reuse `filterPairsByLocalSearch` — do not fetch all pairs from chain on outage. - Factory gate: degraded results must still be `factorySet.has(addr)`. - Preserve indexer-first path when healthy; degraded is **only** on `pairsQuery.isError` (not loading). - Selected pair prepend behavior unchanged (current value stays visible during non-matching search). - Token name seeding: use CW20 instantiate `name` field already present; ensure indexer ingests token metadata (factory/token discovery path) — do not hard-code names only in frontend. - `PAIR_SEARCH_MIN_CHARS` (2) and debounce (300ms) unchanged. - No new indexer API surface required for degraded mode. ## Relevant files | Area | Path | |------|------| | Combobox | `frontend-dapp/src/components/trade/PairSearchSelect.tsx` — `options` memo, `fallbackAddresses`, `showEmptyState` | | Local filter | `frontend-dapp/src/utils/pairSearchQuery.ts` | | Unit tests | `frontend-dapp/src/utils/__tests__/pairSearchQuery.test.ts` | | Component tests | New: `PairSearchSelect` degraded-mode test (mock indexer error) | | Deploy seed | `scripts/deploy-dex-local.sh` — Phase 2 token instantiate, indexer bootstrap | | Indexer assets | `indexer/src/indexer/parser.rs` / token discovery — ensure `name` persisted | | Relevance SQL | `indexer/src/db/queries/pairs.rs` | | Indexer test | `indexer/tests/api_pairs.rs` | | Docs | `docs/frontend.md` § Pair search combobox invariants | ## Recommended direction ### A. Fix degraded typed search 1. In `PairSearchSelect` `options` memo: when `pairsQuery.isError` **and** `debouncedSearch` is non-empty, populate `result` from `filterPairsByLocalSearch(labelsByAddress, debouncedSearch, PAIR_SEARCH_RESULT_LIMIT)` filtered by `factorySet` (same as `fallbackAddresses` logic — ensure `fallbackAddresses` is used or merge paths). 2. Add subtle degraded indicator (optional): `aria-busy` off, dim "Offline search" hint — align with `AGENTS_FRONTEND_MARKET_DATA_OUTAGE.md` copy patterns; no env URLs. 3. Unit/component test: mock `getPairs` rejection → type `emb` → options include Ember/Coral factory pairs. ### B. Seed token names on LocalTerra QA deploy 1. Confirm deploy instantiate msgs set distinct `name` values (already `TOKEN_NAMES`). 2. Trace why indexer shows `name=''` post-deploy — fix asset upsert from CW20 token info query if metadata is dropped. 3. Add deploy verification step or `scripts/qa/` check: `GET /api/v1/pairs?q=ember&sort=relevance` returns tier-2/3 hits after indexer sync. 4. Document in `scripts/qa/README.md` manual matrix row for token name search. ## Acceptance criteria - [ ] Indexer stopped + typed query `EMBER` in Trade/Limits combobox returns matching factory pairs (not empty state). - [ ] Indexer healthy path unchanged (no local filter when API succeeds). - [ ] Empty query degraded mode still lists top factory pairs. - [ ] After `make deploy-local` + indexer sync, `q=Ember` (name substring) returns relevant pairs in live API test. - [ ] Frontend + indexer tests added/updated. - [ ] #314 can close after manual QA matrix re-run. ## Test plan — all paths | Path | Expected | |------|----------| | Indexer up, typed search | Indexer relevance results | | Indexer up, empty query | `volume_24h desc` default list | | Indexer down, empty query | Up to 20 factory pairs from labels | | Indexer down, typed `EMBER` | Local substring matches | | Indexer down, typed `zzzzz` | "No pairs match your search" | | Indexer down, `terra1…` address | Local label/addr match if in factory set | | Selected pair + non-matching query | Current selection prepended | | Post-deploy API `q=Ember` | Tier 2/3 hit with non-empty `assets.name` | ## Test plan — attack / abuse / hack vectors | Vector | Expected | |--------|----------| | Indexer SSRF / error injection | Client only filters local factory labels — no arbitrary URL fetch | | Oversized `q` (>128) | Indexer rejects when up; local filter truncates/ignores per `PAIR_LIST_Q_MAX_LEN` when down | | Factory set bypass via degraded search | Results always filtered `factorySet.has(addr)` | | Unicode / case homoglyph in local filter | `toLowerCase` + `includes` — no crash; bounded result count | ## Verification criteria - [ ] `make test-frontend` green (new degraded-mode test). - [ ] Manual: stop indexer tmux session → `/limits` → type `EMBER` → options appear. - [ ] `curl '/api/v1/pairs?q=Ember&sort=relevance'` on LocalTerra returns hits with populated token names. - [ ] Re-run #314 verification matrix (≥6 pairs) — no FAIL on degraded typed search or tier 2.
PlasticDigits commented 2026-06-05 13:44:12 +00:00 (Migrated from gitlab.com)

marked as related to #314

marked as related to #314
ghost1 commented 2026-06-05 13:55:54 +00:00 (Migrated from gitlab.com)

mentioned in commit fd54fb6ce2

mentioned in commit fd54fb6ce27308d55471c0ac66e85f6f3b82eb01
PlasticDigits commented 2026-06-05 13:56:15 +00:00 (Migrated from gitlab.com)

mentioned in merge request !812

mentioned in merge request !812
PlasticDigits commented 2026-06-05 13:56:22 +00:00 (Migrated from gitlab.com)

Implementation complete — MR !812

MR: https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/94

Changes

  • Frontend: Per-pair local search haystacks (label + addresses + cached CW20 symbol/name) fix degraded typed search when menu labels only show shortened addresses. Offline search hint in combobox.
  • Indexer: resolve_asset refreshes CW20 metadata when DB name/symbol are empty.
  • QA: ./scripts/qa/verify-issue-328.sh; docs in docs/frontend.md and scripts/qa/README.md.

Verification (agent)

Item Result
pairSearchQuery.test.ts + PairSearchSelect.degraded.test.tsx (8 tests) PASS
cargo check indexer PASS
Live q=Ember API SKIP (indexer not running on VM)
Manual #314 matrix SKIP (post-merge)

Issue left open until MR merges and manual QA passes.

## Implementation complete — MR !812 **MR:** https://gitlab.com/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/94 ### Changes - **Frontend:** Per-pair local search haystacks (label + addresses + cached CW20 symbol/name) fix degraded typed search when menu labels only show shortened addresses. Offline search hint in combobox. - **Indexer:** `resolve_asset` refreshes CW20 metadata when DB `name`/`symbol` are empty. - **QA:** `./scripts/qa/verify-issue-328.sh`; docs in `docs/frontend.md` and `scripts/qa/README.md`. ### Verification (agent) | Item | Result | |------|--------| | `pairSearchQuery.test.ts` + `PairSearchSelect.degraded.test.tsx` (8 tests) | PASS | | `cargo check` indexer | PASS | | Live `q=Ember` API | SKIP (indexer not running on VM) | | Manual #314 matrix | SKIP (post-merge) | Issue left **open** until MR merges and manual QA passes.
ghost1 commented 2026-06-05 14:31:36 +00:00 (Migrated from gitlab.com)

mentioned in commit 15d38d53d6

mentioned in commit 15d38d53d6d75dbb701d0e7aa004a89e25727493
PlasticDigits commented 2026-06-05 14:33:26 +00:00 (Migrated from gitlab.com)

mentioned in commit 9134e2843f

mentioned in commit 9134e2843ff06a6450988dba6f8f12115c296e7a
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-06-05 14:33:26 +00:00
PlasticDigits commented 2026-06-08 08:43:13 +00:00 (Migrated from gitlab.com)

mentioned in commit d7d1b4c937

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

mentioned in commit 938706dc65

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

mentioned in commit 587f157475

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

mentioned in commit 81784caa84

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

mentioned in commit 995674b775

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

mentioned in commit 995674b775

mentioned in commit 995674b7759a81f43f65bf660a8f5ef9223842aa
PlasticDigits commented 2026-07-12 11:13:49 +00:00 (Migrated from gitlab.com)

mentioned in issue #481

mentioned in issue #481
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#328
No description provided.