Frontend: indexer candle parsing hardening and stale getCandles race tests #226
Labels
No labels
agent:fix_bugfix
agent:fix_conflicts
agent:fix_security
agent:gap_analysis
agent:implement
agent:implement
agent:implement
agent:open_issues
agent:ready
agent:research
agent:security_audit
agent:verify
architecture
backend
blocker:hybrid
blocker:launch
blocker:limit-orders
blocker:v2
block:log_only
block:security
bug
ci
contracts
correctness
deploy
dev
devops
docs
documentation
duplicate
e2e
enhancement
epic
feature
frontend
functional-completion
gas
good first issue
governance
help wanted
high-risk
hooks
hybrid
indexer
infra
infrastructure
integrators
invalid
launch-blocker
limit-orders
localnet
localterra
low priority
missing-implementation
needs-design
ops
performance
priority
high
priority
medium
product
qa
QA
question
ready
ready
research
scripts
security
security-hardening
smartcontracts
tech-debt
testing
ux
UX
v2
verification
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
code/cl8y-dex-terraclassic#226
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Harden indexer candle → chart point mapping and React Query candle fetching so malformed or reordered API responses cannot crash the trade workspace or paint the wrong pair. Pure parsing tests stay in default Vitest; race tests use mocked
getCandlesdelays.Bundled scope:
priceChartCandlesedge cases · out-of-ordergetCandles(stale pair wins)Current codebase
frontend-dapp/src/components/charts/priceChartCandles.ts— filters rows missingopen/close;parseFloaton OHLC/volumefrontend-dapp/src/components/charts/__tests__/priceChartCandles.test.ts— empty input, drop empty open/close, sort, volume quote/basefrontend-dapp/src/components/charts/PriceChart.tsx—useQuery(['candles', pairAddress, interval]),placeholderDatafor interval-only (#148)PriceChartEmptyState.tsx; tests inPriceChart.test.tsxfor[]and all-invalid rowspriceChartCandlesPlaceholder.ts—keepPreviousCandlesForIntervalSwitchindexerCandlesToChartPointsdoes not validateNaN, extreme floats, or partial field garbage beyond the open/close presence check.Why this is needed
1e309,NaN, objects) should not propagate into lightweight-charts and throw duringsetData.Constraints and guardrails
lightweight-chartsimport inpriceChartCandles.tstests.dangerouslySetInnerHTMLon candle fields (already true; verify in tests).npm run test:runonly — no Postgres for these tests.Relevant files
frontend-dapp/src/components/charts/priceChartCandles.tsfrontend-dapp/src/components/charts/__tests__/priceChartCandles.test.tsfrontend-dapp/src/components/charts/PriceChart.tsxfrontend-dapp/src/components/charts/priceChartCandlesPlaceholder.tsfrontend-dapp/src/components/charts/__tests__/PriceChart.test.tsxfrontend-dapp/src/services/indexer/client.ts(mock only)docs/frontend.md,skills/AGENTS_FRONTEND_PRICE_CHART.md,skills/AGENTS_FRONTEND_TRADE_PAIR_SWITCH.mdRecommended direction
priceChartCandles.test.ts: Non-numericopen/close,NaN/Infinityresults, mixed valid/invalid rows, missinghigh/low, zero-length strings, absurdopen_time(invalid date → drop or stable sort).parseFloat('')→NaNpoints are filtered (likely addNumber.isFiniteguard on mapped numbers).PriceChart.test.tsxrace: MockgetCandleswith delayed resolves forpairAvspairB; switch topairBbeforepairAreturns; assert headline/canvas props reflect B only.pairAddressref guard inPriceChart(only with failing test first).Acceptance criteria
priceChartCandles.test.tscovers malformed/extreme numeric inputs; noNaNin output series.PriceChart.test.tsx(or dedicated test) proves stale slowergetCandlesdoes not overwrite newer pair data.[], all-invalid open/close).priceChartCandles.tscomment +docs/frontend.mdif behavior changes.test.skip.Test plan — functional paths
[]/undefined[]open: ''open: 'abc'NaN/Infinitystringsclose: 'NaN'1e309Test plan — attack vectors
openas object/array<script>inopen_timeopen_timeVerification criteria
cd frontend-dapp && npm run test:run— all candle + PriceChart tests green.npm run test:charts(uses fixtures, not indexer)./trade— chart matches URL pair.skills/AGENTS_FRONTEND_TRADE_PAIR_SWITCH.mdif race guard added.Related issues
marked as related to #211
marked as related to #148
marked as related to #180
marked as related to #113
mentioned in commit
fe73f455b1Implementation summary (#226)
Hardened the indexer candle → chart trust boundary and added automated coverage for stale
getCandleson pair switch.Code
priceChartCandles.ts: Rows are dropped (not coerced) unlessopen/closeare present,open_timeparses to a finite Unix second, and all OHLC fields areNumber.isFiniteafterparseFloat(coversNaN,Infinity,1e309, non-numeric strings, emptyhigh/low). Exported helpersparseChartFiniteNumber/candleOpenTimeSecondsfor tests.priceChartCandles.test.ts: Malformed/extreme/mixed-batch/duplicate-timestamp cases; asserts noNaNin output.PriceChart.test.tsx: does not apply stale slower getCandles after switching to a faster pair — delayed mock for pair A, fast pair B; verifies OHLC/headline stay on B after A resolves. No extra ref guard was needed (React Query key + cancellation sufficient).Docs / agent playbooks
getCandleson pair switchTests run (green)
cd frontend-dapp && npm run test:run(697 tests)npm run test:charts(15 tests)Merged to
mainatfe73f45.Verification checklist
cd frontend-dapp && npm run test:run—priceChartCandles.test.ts+PriceChart.test.tsxgreennpm run test:charts— no regression/trade: rapid pair switch — chart headline and candles match URL pair (no flash of prior pair)price-chart-interval-loading), not full remount@brouie — please verify the checklist above on your environment when convenient. Leaving this issue open until QA sign-off.
mentioned in issue #211
Verification complete (GitLab #226)
Verified on worktree
verify/issue-226againstmain@54a6346(includes prior implementation @fe73f45).What was checked
Automated (all green)
cd frontend-dapp && npm run test:run— 710 tests passed (includes 16priceChartCandles+ 20PriceChartcases)npm run test:charts— 21 passed, 1 pre-existing skip (real-library perf guard)test.skipin candle/chart testsImplementation invariants (confirmed)
priceChartCandles.ts: drop-row policy withNumber.isFiniteon all OHLC + validopen_time; exportedparseChartFiniteNumber/candleOpenTimeSecondsPriceChart.tsx: React Query key['candles', pairAddress, interval]+ canvaskey={pairAddress}— no ref guard needed (unit test proves cancellation sufficient)dangerouslySetInnerHTMLin chart componentsDocs / agent playbooks (cross-linked)
Manual (localnet)
:5173against indexer:3001+ LocalTerra LCD:1317/tradechart headline and candles match URL pairVerification checklist
npm run test:run—priceChartCandles.test.ts+PriceChart.test.tsxgreennpm run test:charts— no regression/trade: pair switch via selector — chart/headline track selected pair (no stale-prior-pair flash)price-chart-interval-loading), not full remountAll acceptance criteria and verification criteria from the issue body pass. Closing.
mentioned in issue #524
mentioned in issue #543
marked as related to #543
mentioned in issue #568
mentioned in issue #680
mentioned in issue #705
mentioned in issue #717