TimeCurve Protocol view: 'Indexer unreachable' banner is misleading when indexer IS serving data #49

Closed
opened 2026-04-23 04:08:16 +00:00 by Brouie · 4 comments
Brouie commented 2026-04-23 04:08:16 +00:00 (Migrated from gitlab.com)

Filed per dev request from #39 section C5 findings.

Summary

Protocol view shows 'Indexer: unreachable (http://127.0.0.1:3100)' banner even though the canonical fee sink distribution data below the banner IS rendering correctly — meaning the indexer is clearly reachable and serving data.

Observed

  • Banner text: 'Indexer: unreachable (http://127.0.0.1:3100)'
  • Directly below the banner: 'Canonical fee sinks (read-only)' section renders correctly with per-block fee distributions:
    • DOUB/CL8Y LP (locked): 0.297 CL8Y
    • CL8Y burned (sale proceeds): 0.397 CL8Y
    • Podium pool: 0.198 CL8Y
    • Team/reserved: 0 CL8Y
    • Rabbit Treasury: 0.0991 CL8Y
  • Data is live, matches FeeRouter + PARAMETERS.md splits

Likely cause

Either:

  • Stale status indicator not refreshing
  • Banner reads a different health endpoint than the data queries (possibly /health vs /v1/*, or a stale initial-fetch flag not cleared on success)

Impact

  • Misleading to users: appears indexer is down when it's fully operational
  • Could mask a real outage in the future (signal:noise ratio broken)

Environment

  • Same session as YO #47 and #48
  • Anvil 31337 local stack, indexer on :3100, frontend localhost:5173
  • Section C5 context from #39

Screenshot

C5-indexer-banner-misleading

cc @PlasticDigits

**Filed per dev request from #39 section C5 findings.** ## Summary Protocol view shows 'Indexer: unreachable (http://127.0.0.1:3100)' banner even though the canonical fee sink distribution data below the banner IS rendering correctly — meaning the indexer is clearly reachable and serving data. ## Observed - Banner text: *'Indexer: unreachable (http://127.0.0.1:3100)'* - Directly below the banner: 'Canonical fee sinks (read-only)' section renders correctly with per-block fee distributions: - DOUB/CL8Y LP (locked): 0.297 CL8Y - CL8Y burned (sale proceeds): 0.397 CL8Y - Podium pool: 0.198 CL8Y - Team/reserved: 0 CL8Y - Rabbit Treasury: 0.0991 CL8Y - Data is live, matches `FeeRouter` + `PARAMETERS.md` splits ## Likely cause Either: - Stale status indicator not refreshing - Banner reads a different health endpoint than the data queries (possibly `/health` vs `/v1/*`, or a stale initial-fetch flag not cleared on success) ## Impact - Misleading to users: appears indexer is down when it's fully operational - Could mask a real outage in the future (signal:noise ratio broken) ## Environment - Same session as YO #47 and #48 - Anvil 31337 local stack, indexer on :3100, frontend localhost:5173 - Section C5 context from #39 ## Screenshot ![C5-indexer-banner-misleading](/uploads/386e21781be6d0eeec2c2f2127ef4984/image.png) cc @PlasticDigits
Brouie commented 2026-04-23 04:09:25 +00:00 (Migrated from gitlab.com)

mentioned in issue #39

mentioned in issue #39
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-04-23 05:33:23 +00:00
PlasticDigits commented 2026-04-23 05:33:40 +00:00 (Migrated from gitlab.com)

Fix merged (cc @Brouie)

What we changed
IndexerStatusBar only called `GET /v1/status`. If that request fails (network, 404, or in practice client-side blocklists that target paths containing status) while the rest of the indexer is healthy, the bar showed "Indexer: unreachable" even though the footer already used working v1 routes (e.g. `/v1/fee-router/fees-distributed`).

`fetchIndexerStatus()` in `frontend/src/lib/indexerApi.ts` now:

  1. Tries `/v1/status` first (unchanged shape: schema + `max_indexed_block` from the indexer DB when available).
  2. If that is missing or not OK, falls back to the same read we trust for the footer: `GET /v1/fee-router/fees-distributed?limit=1&offset=0`, and builds a status object from `X-Schema-Version` and the latest row’s `block_number` (or `max_indexed_block: null` if the table is empty but the server responds).

Covered in `frontend/src/lib/indexerApi.test.ts` (Vitest): primary path, fallback, and null when both fail.

Verification checklist for @Brouie

  • Local stack: Anvil 31337, indexer on :3100, `VITE_INDEXER_URL=http://127.0.0.1:3100`, `npm run dev` in `frontend/`.
  • With indexer up: footer Canonical fee sinks shows data; the header/footer Indexer line is green and reads "Indexer v… · latest indexed block … · live" (not unreachable).
  • `GET http://127.0.0.1:3100/v1/status` returns 200 in the same session (browser or curl) — confirms primary path.
  • Optional stress: simulate a failed `/v1/status` only (e.g. block that URL in devtools / proxy); confirm bar still recovers to live via the fee-router fallback while fee data in the footer still loads.
  • `cd frontend && npx vitest run src/lib/indexerApi.test.ts` passes.

Pushed to `main` (merge includes commit `e7ce289` and merge `39069d1`).

## Fix merged (cc @Brouie) **What we changed** `IndexerStatusBar` only called \`GET /v1/status\`. If that request fails (network, 404, or in practice **client-side blocklists** that target paths containing `status`) while the rest of the indexer is healthy, the bar showed **"Indexer: unreachable"** even though the footer already used working v1 routes (e.g. \`/v1/fee-router/fees-distributed\`). \`fetchIndexerStatus()\` in \`frontend/src/lib/indexerApi.ts\` now: 1. Tries \`/v1/status\` first (unchanged shape: schema + \`max_indexed_block\` from the indexer DB when available). 2. If that is missing or not OK, **falls back** to the same read we trust for the footer: \`GET /v1/fee-router/fees-distributed?limit=1&offset=0\`, and builds a status object from \`X-Schema-Version\` and the latest row’s \`block_number\` (or \`max_indexed_block: null\` if the table is empty but the server responds). Covered in \`frontend/src/lib/indexerApi.test.ts\` (Vitest): primary path, fallback, and null when both fail. **Verification checklist for @Brouie** - [ ] Local stack: Anvil 31337, indexer on :3100, \`VITE_INDEXER_URL=http://127.0.0.1:3100\`, \`npm run dev\` in \`frontend/\`. - [ ] With indexer up: footer **Canonical fee sinks** shows data; the header/footer **Indexer** line is green and reads **"Indexer v… · latest indexed block … · live"** (not *unreachable*). - [ ] \`GET http://127.0.0.1:3100/v1/status\` returns 200 in the same session (browser or curl) — confirms primary path. - [ ] Optional stress: simulate a failed \`/v1/status\` only (e.g. block that URL in devtools / proxy); confirm bar still recovers to **live** via the fee-router fallback while fee data in the footer still loads. - [ ] \`cd frontend && npx vitest run src/lib/indexerApi.test.ts\` passes. Pushed to \`main\` (merge includes commit \`e7ce289\` and merge \`39069d1\`).
PlasticDigits (Migrated from gitlab.com) reopened this issue 2026-04-23 05:41:02 +00:00
Brouie commented 2026-04-23 06:24:53 +00:00 (Migrated from gitlab.com)

mentioned in issue #42

mentioned in issue #42
Brouie commented 2026-04-24 02:39:33 +00:00 (Migrated from gitlab.com)

@PlasticDigits verified.

Root cause identified was spot-on — client-side blocklists against path segments containing 'status' would filter /v1/status requests while other v1 routes functioned normally. That matches exactly the misleading banner I reported where fee sink data rendered below while the banner claimed unreachable.

Verification

Code-level:

  • indexerApi.ts::fetchIndexerStatus() now two-tier: primary GET /v1/status (best signal, includes DB pointer + max block), fallback GET /v1/fee-router/fees-distributed?limit=1 if primary fails. Only returns null when BOTH fail.
  • IndexerStatusBar.tsx logic unchanged at component level — correctly shows 'unreachable' only if the two-tier check returns null.

Tests:

  • indexerApi.test.ts: 14/14 passing, including explicit cases:
    • 'returns /v1/status JSON when that route is healthy'
    • 'falls back to fees-distributed when /v1/status is not OK'
    • 'returns null when both status and fallback fail'

Good fix for a real false-negative pattern. Closing as verified.

@PlasticDigits verified. Root cause identified was spot-on — client-side blocklists against path segments containing 'status' would filter `/v1/status` requests while other v1 routes functioned normally. That matches exactly the misleading banner I reported where fee sink data rendered below while the banner claimed unreachable. ## Verification Code-level: - `indexerApi.ts::fetchIndexerStatus()` now two-tier: primary `GET /v1/status` (best signal, includes DB pointer + max block), fallback `GET /v1/fee-router/fees-distributed?limit=1` if primary fails. Only returns null when BOTH fail. - `IndexerStatusBar.tsx` logic unchanged at component level — correctly shows 'unreachable' only if the two-tier check returns null. Tests: - `indexerApi.test.ts`: 14/14 passing, including explicit cases: - 'returns /v1/status JSON when that route is healthy' - 'falls back to fees-distributed when /v1/status is not OK' - 'returns null when both status and fallback fail' Good fix for a real false-negative pattern. Closing as verified.
Brouie (Migrated from gitlab.com) closed this issue 2026-04-24 02:39:34 +00:00
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/yieldomega#49
No description provided.