- /api/ai/ask: at most AI_MAX_CONCURRENT_PER_WORKER (12 of 32 threads) answers per worker;
beyond that 503 assistant_busy + Retry-After before any quota is reserved. Without it a
burst of questions (3-40 s each) took every thread and the map and quizzes queued behind.
The slot is held until the stream is actually finished or closed.
- Answer submission 21 -> 14 queries, 15.4 -> 11.0 ms: one query for all choices, locked
get_or_create for node progress and streak, and today's streak recorded once per day
via the cache instead of a transaction per answer.
- /api/home 12.4 -> 8.6 ms: the user's completions are read by user_id instead of an IN list
of ~600 lesson ids; the dict is returned directly (serializer stays the Swagger contract,
HomeMatchesItsSerializerTests keeps them equal).
- otp_login per-IP 30 -> 300/hour: a class of 30 on one school Wi-Fi filled it; guessing is
bounded per code and per phone.
- /api/health aiConcurrency.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>