fix(api): cap /candles/:slab date-span to what MAX_BARS can hold [BUG-008] - #217
fix(api): cap /candles/:slab date-span to what MAX_BARS can hold [BUG-008]#217Morenikeoa wants to merge 1 commit into
Conversation
…-008] The route validated from < to but never bounded the SPAN. The existing row cap (MAX_BARS * 10 = 50,000 rows via .limit()) only bounds the RESULT size — Postgres still has to scan/sort the full set of matching rows for the requested date range (filtered by slab + network, ordered by created_at ascending) to find the first 50,000, which is unbounded work for a multi-year range on a high-volume market regardless of how few rows are eventually returned or how small the final candle count is. Cap the span to MAX_BARS * bucketSeconds — scaled per resolution, so the limit is proportional to what could actually produce MAX_BARS buckets at that resolution (~3.5 days at 1-minute resolution, ~13.7 years at daily), rather than a flat arbitrary cutoff that would be wrong at either end. Two existing tests used from=0&to=9999999999 as a "don't care about the range" placeholder; narrowed to realistic windows since their actual intent was exercising basic data flow, not wide-range behavior. Added a regression test (multi-year range at 1-minute resolution is rejected without ever calling the DB; exact-max-span and resolution-scaling are accepted). Verified it fails against the pre-fix code (200 instead of 400) and passes against the fix. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@Princessdada is attempting to deploy a commit to the Khubair Nasir's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
Warning Review limit reached
More reviews will be available in 28 minutes and 3 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Problem
GET /candles/:slabvalidatesfrom < tobut never bounds the span between them. The existing protection —.limit(MAX_BARS * 10)(50,000 rows) on the trades query — only bounds the result size that comes back, not the work Postgres has to do to produce it: the query filters byslab_address+network, orders bycreated_atascending, and takes the first 50,000 rows. For a multi-year requested range on a high-volume market with more historical trades than that, the DB still has to scan/sort the full matching row set for that date range to find the first 50,000 in order, regardless of how small the eventual response ends up being after bucketing.Fix
Added a max-span check:
MAX_BARS * bucketSeconds. This scales with the requested resolution rather than being a flat constant — a flat cap would be wrong at either end (too restrictive for daily candles, too permissive for 1-minute candles). At 1-minute resolution the max span is ~3.5 days; at daily resolution it's ~13.7 years — both are exactly "the widest range that could still produce ≤ MAX_BARS buckets," which is the actual invariant this protects.Two existing tests used
from=0&to=9999999999as a "don't care about the exact range" placeholder spanning ~316 years; narrowed both to realistic windows since their actual intent was exercising basic data flow with a mocked Supabase response, not wide-range behavior.Proof of Fix
New tests: a multi-year range at 1-minute resolution is rejected with a 400 before the Supabase query is ever issued; a range exactly at the computed max span is accepted; a multi-year range at daily resolution (where it's legitimately within bounds) is accepted.
Verified this is a genuine regression test: reverted just the source change and reran — the multi-year-range test failed with a 200 instead of 400 (the query would have gone through unbounded). Restored the fix and it passes.
tsc --noEmitclean (no separate lint script in this repo).Test Output
Full suite: 297/298 passed (294 baseline + 3 new). The 1 failure (
tests/sdk-smoke.test.ts) is pre-existing and unrelated — it asserts on an exact@percolatorct/sdkerror-message string that has drifted from the locally-resolved SDK version in this environment.Related
Found during a broader API audit. Distinct from open issue #201 (
MAX_BARSnot capping the output bar count even with the row limit applied) — that's a separate root cause (output bucket-count bound vs. this fix's input date-span bound); both are needed, neither subsumes the other. No existing open issue/PR covers this specific date-span gap.