Repository navigation
Studio workflow status polls are metered on the AI budget and drain the shared ai:<ip> bucket #1517
Description
Summary
#1507 added /api/workflows to AI_ROUTE_PREFIXES in apps/web/src/proxy.ts. isAiRoute classifies by path prefix only, so the frequently-polled GET status endpoint is metered against the AI budget (UVAI_AI_RATE_LIMIT_PER_MINUTE, default 12/min) alongside the POST that starts a run.
pollVideoToActions in apps/web/src/lib/studio-workflow.ts polls at attempts = 20, delayMs = 1500 — 40 requests/min. The start POST shares the same bucket, so one run issues 21 AI-class requests inside a ~30s window.
The 12th request 429s, roughly 17 seconds into a 30-second poll window — before a run that does a transcript fetch plus an action-agent call can plausibly finish. Studio reaches its Still running after N polls branch on essentially every run, so "Act on findings" reads as broken rather than slow.
Why it is worse than one endpoint being throttled
The rate-limit bucket is keyed by class, not by path:
const routeClass = isAiRoute(pathname) ? 'ai' : 'api';
const key = `${routeClass}:${clientIp}`;Every entry in AI_ROUTE_PREFIXES shares one ai:<ip> counter. A single Studio run therefore drains the allowance that /api/chat, /api/transcribe, /api/pipeline, /api/extract-events and /api/agents/dispatch draw from, for the remainder of the 60s window. A user who clicks the new button then finds chat and transcription 429ing as collateral.
Current state
Present on main as of 5135f4e (#1507, merged 2026-08-07 21:22 UTC). The finding was raised on #1507 by the Vercel Agent review and in a follow-up comment, but the PR merged without it addressed.
Acceptance criteria
-
GET/HEADon/api/workflowsis not metered against the AI budget. -
POSTto/api/workflows/video-to-actionsstays AI-class — it does real model work. - The exemption is scoped per-prefix, not a blanket
GETcarve-out across all AI routes. - Poll cadence leaves meaningful headroom under whichever budget applies, rather than sitting just beneath the ceiling.
- The classification is covered by tests that run in CI (
test-frontend, added in ci: run apps/web vitest as required test-frontend job (#1449) #1480), including a control proving the fix does not over-exempt.
Notes
isAiRoute currently lives in proxy.ts, which imports next/server and so is awkward to unit test. apps/web/src/lib/auth-paths.ts exists precisely as the home for path policy "free of Next.js request types so vitest can import it offline" and already hosts the sibling shouldSkipRateLimit. Moving the classifier there makes it testable without a Next.js request harness.
Activity
linear-code commentedon Aug 7, 2026
GRV-399
coderabbitai commentedon Aug 7, 2026
🔗 Related PRs
#225 - fix: eliminate internal HTTP loopback in /api/video Strategy 3 — run through Vercel router directly [merged]
#313 - fix(pipeline): stream API key on job poll, async jobs, smoke SSE path [merged]
#314 - fix(pipeline): async kickoff uses videos/process [merged]
#572 - feat(web): AI video generation via Vercel AI Gateway (Google Veo 3.1) — supersedes
#365[merged]#658 - fix(web): fail open for cheap AI status GETs, closed only for paid AI calls (follow-up to
#655) [merged]📝 Issue Planner
Check the box below or use the
@coderabbitai plancommand to generate an implementation plan and prompts that you can use with your favorite coding assistant.🧪 Issue enrichment is currently in open beta.
You can configure auto-planning by selecting labels in the issue_enrichment configuration.
To disable automatic issue enrichment, add the following to your
.coderabbit.yaml:💬 Have feedback or questions? Drop into our discord!
github-actions commentedon Aug 7, 2026
👋 Thanks for opening this issue! It has been automatically labeled for triage.