feat/pub-api-rl
needs attentionviewing older commit28ed416 · incrementalPR #266reviewed 2026-07-08 17:41 UTC0H · 1M · 4L · 1I- 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)'
- 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+140−25.claude/rules+3−2
- Blast
- 4 files total (+143/-27 across platform API utils and docs). Rate-limit logic only; no contract, schema, handler, or DB changes.
Findings · 6
correctness1
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
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.
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
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.
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.
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
- edc190esafeincremental0H · 0M · 3L2026-07-09 00:52
- 1f85ae7needs attentionincremental0H · 1M · 4L2026-07-08 20:16
- d77720dneeds attentionincremental0H · 1M · 4L2026-07-08 18:03
- 28ed416needs attentionincremental0H · 1M · 4L2026-07-08 17:41current
- ae8bb22safeincremental0H · 0M · 9L2026-07-07 20:38
- c095510needs attentionfull3H · 3M · 4L2026-07-07 19:36