Conversation
Introduces a BusyLoopDetector class that monitors call frequency within a time window and raises an error if a threshold is exceeded. Integrated into ProjectDatabase.get_items(). Also updated README to point candidates to api/pagination.py. https://claude.ai/code/session_01MMKGE3aKehnxGfV8H6uvNt
…r reset - Move detector from per-instance to module-level so it persists across ProjectDatabase instantiations. Previously, get_page() creating a new ProjectDatabase each call meant candidates looping over get_page() would get a fresh detector every iteration, defeating the protection. - Reset counter to 1 (not 0) in _reset_timer so the call that triggers the window reset is properly counted in the new window. https://claude.ai/code/session_01MMKGE3aKehnxGfV8H6uvNt
…tAr' into claude/add-busy-loop-detector-DbtAr
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
|
|
||
| try { | ||
| const response = await fetch(url, { signal: controller.signal }); | ||
| return response.json(); |
There was a problem hiding this comment.
Missing await makes timeout not cover body reading
Medium Severity
return response.json() without await inside the try/catch/finally causes the finally block to run (clearing the timeout via clearTimeout) immediately after headers arrive, before the response body is fully read. This means the abort timeout only protects the initial fetch, not the body reading phase. Additionally, if response.json() rejects, the catch block is bypassed entirely, so an AbortError during body reading would never be converted to a ProjectsRequestTimeoutError. Using return await response.json() would fix both issues.


This matches the typescript interview question. It's a little different
Testing
Added
to part 2 of api/pagination.ts