← all branches

feat/pub-api-rl

needs attentionviewing older commit
28ed416 · incrementalPR #266reviewed 2026-07-08 17:41 UTC0H · 1M · 4L · 1I
The branch
Purpose
Raise public API v1 rate-limit budgets from the dashboard's internal defaults (too low for machine clients) to published limits suitable for external integrators.
Goal
External API clients get generous, explicitly-documented rate budgets; the limiter and its identity/classification logic are extracted, unit-tested, and pinned by a regression guard.
Sub-goals
  • SG-1: Raise read budget from 200/15min (~13/min) to 300/min and write from 50/15min to 60/min
  • SG-2: Decouple public-v1 budgets from dashboard DEFAULT_RATE_LIMITS (separate constant, no implicit inheritance)
  • SG-3: Pin published budgets with a regression test so a merge cannot silently revert them
  • SG-4: Fix stale api-patterns.md doc that still claimed 'no rate limit (deferred)'
The changes (whole branch)
What
v1 route.ts: explicit RATE_LIMIT_BUDGETS constant (auth 10/min, read 300/min, write 60/min) replaces DEFAULT_RATE_LIMITS reference. Rate-limit config + bucketing extracted to public-v1-rate-limit.ts. Regression test added. api-patterns.md updated. This (final) commit: comment trimming, doc precision, one new test case for method-specificity.
Why
A prospective API client asked about limits before integrating. The old cap (200/15min ≈ 13/min) was inherited from the browser-session limiter — far too low for historical backfills or large-portfolio polling. Usage volume is already governed by credits, so rate limits only need to protect stability.
Areas
apps/platform+14025.claude/rules+32
Blast
4 files total (+143/-27 across platform API utils and docs). Rate-limit logic only; no contract, schema, handler, or DB changes.
in-memory limiter is per-instance (not a hard global quota) shared-store limiter noted as future follow-up for enterprise SLA caps
CI checks· GitHub status check API inaccessible (rate limit)CodeRabbit· No .coderabbit.yaml present

Findings · 6

correctness1

low

Test at line ~70 still says 'sliding-window key' but middleware is fixed-window

apps/platform/src/api/utils/__tests__/public-v1-rate-limit.test.ts:70

api-patterns.md was correctly updated in this diff to say 'fixed-window'; the test description at line ~70 (rateLimitBucket describe block) still says 'sliding-window key'. Pre-existing, but newly inconsistent with the doc.

tests2

medium

New test for GET /auth/token is incomplete — non-GET/non-POST methods on that path untested

apps/platform/src/api/utils/__tests__/public-v1-rate-limit.test.ts:27

The added test proves GET /auth/token → read, but does not cover PUT/DELETE/PATCH on that path (which fall to 'write' by the else branch). Given the test's goal of proving method-specificity of the auth budget, a second case (e.g. DELETE) would complete the assertion.

low

Regression guard comment lost historical context (old 200/15min cap, PR #266)

apps/platform/src/api/utils/__tests__/public-v1-rate-limit.test.ts:11

Original said 'the old 200/15min read cap' and 'See PR #266'. Without those, a future test failure won't tell the maintainer what value was previously reverted to or where the incident was documented.

improvement3

low

classifyRateLimitKind comment trimming lost the scrypt CPU rationale

apps/platform/src/api/utils/public-v1-rate-limit.ts

Deleted JSDoc noted 'it does scrypt work per call' as the reason POST /auth/token gets the stricter auth budget. Without that, a contributor might raise the auth limit unaware of the per-call CPU cost.

low

rateLimitIdentity comment omits hash algorithm

apps/platform/src/api/utils/public-v1-rate-limit.ts

The replacement comment says 'Hash the credential' without naming createHash('sha256'). Since the window-store key is security-relevant, naming the algorithm makes the isolation guarantee explicit.

info

New test name not parallel with existing describe-block style

apps/platform/src/api/utils/__tests__/public-v1-rate-limit.test.ts:26

File style is declarative ('classifies GETs as read'); 'only treats POST /auth/token as auth — a GET on that path is a read' reads as implementation description. Consider 'classifies GET /auth/token as read, not auth'.

History · 6 commits

  1. edc190esafeincremental0H · 0M · 3L2026-07-09 00:52
  2. 1f85ae7needs attentionincremental0H · 1M · 4L2026-07-08 20:16
  3. d77720dneeds attentionincremental0H · 1M · 4L2026-07-08 18:03
  4. 28ed416needs attentionincremental0H · 1M · 4L2026-07-08 17:41current
  5. ae8bb22safeincremental0H · 0M · 9L2026-07-07 20:38
  6. c095510needs attentionfull3H · 3M · 4L2026-07-07 19:36