TimeCurveProtocolWarbowRefreshSection: pagination guard exhaustion silently truncates candidate set #174
Labels
No labels
agent:fix_bugfix
agent:fix_conflicts
agent:fix_security
agent:gap_analysis
agent:implement
agent:open_issues
agents
agent:security_audit
agent:verify
area
timecurve
arena
arena-v2
audit
block:feature_review
block:security
bug
contracts
design
devops
docs
documentation
enhancement
epic
feature
frontend
indexer
low priority
megaeth
operations
ops
performance
QA
qa checklist
referrals
removal
security
smart-contracts
tech-debt
testing
time-arena
timecurve
visual-qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
code/yieldomega#174
Loading…
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?
Severity: P3 — forward-compat / silent failure mode
split out of #160 follow-up per @PlasticDigits — "all of these findings need to have issues opened for them".
location
frontend/src/pages/timecurve/TimeCurveProtocolWarbowRefreshSection.tsx:100-122(HEAD284c15c):pagination loop exits cleanly when
next_offsetis null/undefined. exits silently whenguard === 50with non-nullnext_offset— no warning state, user sees a candidate count without knowing more wallets were skipped.why it does not bite today
indexer caps SQL DISTINCT at
REFRESH_CANDIDATES_DISTINCT_CAP = 10_000(indexer/src/api.rs). frontend ceiling is50 × limit 500 = 25_000. loop always hits thenext_offset === nullbreak first under current configuration.why it bites later
if the indexer cap is raised in a future schema bump (10k → 50k, 100k, etc.) without bumping the frontend
guardthreshold to match, the truncation becomes silent. user sees N candidates loaded, submits refresh, missing wallets are not considered. no log, no banner, no error.compounds with the broader gas-blowup design ticket (#172) — whichever direction that ticket lands, the pagination guard becomes coupling between indexer cap and frontend ceiling that should be defended in code rather than in coordinated commits.
fix shape
track the last-seen
next_offsetoutside the loop so the post-loop check has visibility:either set
setLoadErrwith a clear copy or introduce a separateloadWarningstate so the load still succeeds but the truncation is observable.acceptance criteria
next_offset === nullcontinues to produce no signalnpm run typecheck+npm testcleanorigin
split from #160 follow-up notes ("Finding 5: P3 silent truncation if pagination guard ever fires"). closely related to #172 (CRITICAL gas-blowup design). filing now per @PlasticDigits.
cc @PlasticDigits
mentioned in issue #175
mentioned in issue #176
mentioned in issue #160
mentioned in merge request !377
Must remove cap completely from indexer
Relation to #172 /
main(a48a353)#172 does not satisfy #174’s acceptance criteria.
TimeCurveProtocolWarbowRefreshSection: when thewhile (guard < 50)loop stops at 50 whilenext_offsetis still non-null, the UI must surface a non-fatal warning (or similar) so operators know the loaded set was truncated.mainstill ends the loop without that post-loop check — same silent path as before.Partial overlap with #172: the indexer DISTINCT cap was removed (schema 1.18.0), so the coupling “indexer cap vs frontend ceiling” called out in #174 is gone on the API side, but the 50-page ceiling remains. With a very large distinct set, guard exhaustion becomes more plausible, so #174’s UX fix is still recommended (and arguably higher priority than when the indexer capped at 10k).
Leaving #174 open; implement the
lastNextOffset+ warning pattern from the issue description when ready.Cross-ref: https://gitlab.com/PlasticDigits/yieldomega/-/issues/172
mentioned in commit
90863894f9Shipped on
main(9086389)Implemented GitLab #174: when
TimeCurveProtocolWarbowRefreshSectionexhausts the client paging loop (50 pages × 500 rows) while the indexer still returns a non-nullnext_offset, the panel now shows a non-fatalStatusMessagewarning(amberwarning-text). Natural completion vianext_offset === nullshows no warning.Code
frontend/src/lib/warbowRefreshCandidatesPagination.ts—accumulateWarbowRefreshCandidatePages, shared capsTimeCurveProtocolWarbowRefreshSection.tsx— wires warning statewarbowRefreshCandidatesPagination.test.tsDocs / invariants
INV-FRONTEND-174-WARBOW-REFRESH-GUARD—docs/testing/invariants-and-business-logic.md§ GitLab #174docs/frontend/timecurve-views.md,docs/testing/strategy.md,docs/testing/manual-qa-checklists.mdskills/README.md,skills/play-timecurve-warbow/SKILL.md; contributor guardrails:.cursor/skills/yieldomega-guardrails/SKILL.mdVerification checklist (for reviewers)
cd frontend && npm run typecheck && npm test— green (305 tests including pagination cases)/timecurve/protocol: load candidates when indexer returnsnext_offset: nullwithin the budget — no yellow warning bannernext_offset) — warning appears, loaded raw row cap ≤ 25,000, finalize UI still usableIssue left open per instructions.
@brouie — please confirm the warning copy and UX meet operator expectations. Thanks!
verified at HEAD
5ca00ec— full pass.source spot-checks (8/8):
accumulateWarbowRefreshCandidatePagesat frontend/src/lib/warbowRefreshCandidatesPagination.ts:29OkwithtruncatedByGuard: booleanflag, orErrfor null responsenext_offset === null) returnstruncatedByGuard: falsetruncatedByGuard: truevariant="warning"renders at :245 when loadWarning is settests:
live walk on fresh stack at HEAD:
Load reference candidates from indexeron protocol pageIndexer merged total (API): 21,Head WarBow hints merged: 0guard-exhaustion path (>25000 candidates) is unit-test covered; not practical to exercise live since swarm produces only ~20-30 wallets per stack lifecycle. willing to mock-test live if you want explicit coverage.
ready for close on your side @PlasticDigits
mentioned in commit
adf5a945e7mentioned in commit
86af4f6a05