Update rate limits configuration and add graph search endpoint#525
Update rate limits configuration and add graph search endpoint#525
Conversation
- Adjusted API rate limits in graph.yml for production environments, reducing multipliers for team and enterprise usage. - Enhanced SEC_MANIFEST to include search rate limits for minute, hour, and day. - Introduced GRAPH_SEARCH category in rate_limits.py and updated related rate limit configurations. - Implemented search rate limiting in search.py, ensuring proper access control for shared repositories. - Updated tests to reflect changes in rate limits and added coverage for new search functionality.
|
@claude please review this PR |
|
Claude finished @jfrench9's task in 2m 25s —— View job PR Review: Update rate limits configuration and add graph search endpointTodo List:
SummaryThe PR is well-structured and the search endpoint integrates cleanly with the existing dual-layer rate limiting system. However, there are two bugs, a significant (likely unintentional) breaking change in production rate limits, and a few minor issues worth addressing before merging. 🐛 Bugs1. Hardcoded user_tier = "ladybug-standard" # ← always hardcodedThe 2. Hardcoded headers={"Retry-After": "60"}, # ← always 60s, even if day-window was exceededThe
|
| Tier | Category | Old effective | New effective | Change |
|---|---|---|---|---|
| ladybug-large | GRAPH_READ | 500 × 2.5 = 1250/min | 120 × 1.5 = 180/min | −86% |
| ladybug-xlarge | GRAPH_READ | 500 × 5.0 = 2500/min | 120 × 2.5 = 300/min | −88% |
| ladybug-large | GRAPH_WRITE | 100 × 2.5 = 250/min | 30 × 1.5 = 45/min | −82% |
| ladybug-large | GRAPH_MCP | 100 × 2.5 = 250/min | 30 × 1.5 = 45/min | −82% |
If this is intentional (infra protection, new baseline more aligned with actual capacity), it should be clearly documented and existing customers notified. If not, the base limits for paid tiers need to be revisited.
🔍 Code Quality
3. Unused req: Request parameter (search.py:108-109, search.py:121-122)
Both search_documents and get_document_section declare req: Request but never use it. FastAPI doesn't require it to be declared if not used. Remove to reduce noise.
4. Stale test function name (test_rate_limits.py:16)
def test_unknown_tier_falls_back_to_free_limits(): # ← "free" no longer existsThe tier was renamed from "free" to "base" in this PR. The test body correctly references "base", but the function name is now misleading.
🧪 Test Gaps
5. AllowedSharedEndpoints.SEARCH not asserted (test_repository_rate_limits.py:15-21)
The new SEARCH = "search" enum member was added to AllowedSharedEndpoints, and _operation_to_category("search") is tested at line 139, but the test_values test doesn't assert AllowedSharedEndpoints.SEARCH.value == "search".
6. No test coverage for _check_search_rate_limit — the new non-shared-repo early-return path, 403 on missing repo_access, and the full rate-limit-exceeded path from search.py have no direct test.
💡 Minor Notes
- The
service.search_documents(graph_id, request)call atsearch.py:115is synchronous (service.search_documents), but the endpoint isasync. If the search service does I/O, it should be awaited or offloaded to a thread pool to avoid blocking the event loop. - The
test_rate_limit_hierarchytest intest_subscription_rate_limits.py:192will pass sincelargeandxlargebase values equalstandard(all 120/min for GRAPH_READ), but it no longer truly validates a hierarchy — consider a note or adjusting the assertion to reflect the multiplier-based approach.
Overall this is a clean refactor and the new GRAPH_SEARCH category is well integrated. The hardcoded tier and Retry-After bugs should be fixed before merge, and the production multiplier reductions deserve explicit sign-off given their impact on paying customers.
- Added 'searches_per_hour' to the service offerings rate limits in offering.py. - Updated user tier retrieval in search.py to fallback to 'ladybug-standard' if not set. - Improved HTTP exception handling to dynamically set 'Retry-After' header based on rate limit response. - Removed unused 'req' parameter from search_documents and get_document_section functions. - Updated tests to reflect changes in rate limit handling and removed unnecessary parameters.
|
@claude can you review the latest changes |
|
Claude finished @jfrench9's task in 1m 48s —— View job Todo List:
Review: Latest Changes (commit
|
| # | Previous Issue | Status |
|---|---|---|
| 1 | Hardcoded user_tier = "ladybug-standard" |
Fixed via getattr fallback |
| 2 | Hardcoded Retry-After: 60 |
Fixed — now uses reset_in from response |
| 3 | Unused req: Request parameter |
Removed from both endpoints |
| 4 | Stale test name (_free_limits) |
Renamed to _base_limits |
| 5 | AllowedSharedEndpoints.SEARCH not asserted |
Added to test_values |
⚠️ Remaining Issue: subscription_tier Not on User Model
The tier fix at search.py:75 is:
user_tier = getattr(current_user, "subscription_tier", None) or "ladybug-standard"subscription_tier doesn't appear to exist on the User model (no matches in robosystems/models/iam/). This means getattr always returns None, and the fallback is always "ladybug-standard" — functionally identical to the original hardcode. The real tier isn't being resolved.
Other rate-limited endpoints (e.g., subscription_aware_rate_limit_dependency in rate_limiting.py:484) hardcode "ladybug-standard" for all authenticated users too, so this is consistent with the current approach. If tier differentiation isn't needed yet, the fallback is fine — but the getattr implies there's an intent to use it later, which will silently not work until the attribute is added.
🔍 Still Open: Minor Code Quality
Synchronous calls in async endpoints (search.py:115, search.py:127):
return service.search_documents(graph_id, request) # sync call in async endpoint
result = service.get_document_section(graph_id, document_id) # sameIf the search service does I/O (OpenSearch HTTP calls), these block the event loop. If it's CPU-only or already uses an async client internally, this is fine — but worth confirming.
test_rate_limit_hierarchy passes trivially (test_subscription_rate_limits.py:192):
assert standard_limit[0] <= large_limit[0] # 120 <= 120 — always passes
assert large_limit[0] <= xlarge_limit[0] # 120 <= 120 — always passesThe base values are intentionally identical across tiers (multiplier applied externally via graph.yml), so the hierarchy test will always pass regardless of whether differentiation is working. Consider testing the multiplier-applied values, or adding a comment explaining why equality is expected.
No test coverage for _check_search_rate_limit — the 403 path on missing repo_access, the rate-limit-exceeded 429 path, and the early return for non-shared repos remain untested.
Overall the critical bugs are resolved and this is in good shape. The subscription_tier attribute question and the sync/async concern are worth a quick decision before merge.
| Branch
Summary
This PR refactors the rate limiting configuration, simplifies its structure, and introduces a new search endpoint for graphs. The changes span rate limit definitions, middleware enforcement, and supporting infrastructure.
Key Accomplishments
Rate Limits Refactor
rate_limits.py): Reduced complexity with a net removal of ~40 lines, streamlining how rate limits are defined and managed across the application.Search Functionality
robosystems/routers/graphs/search.py(+75 lines) to support graph search capabilities..github/configs/graph.yml) to register the new search route.SEC Adapter Update
robosystems/adapters/sec/manifest.py) with additional configuration to support the new functionality.Breaking Changes
Testing Notes
test_rate_limits.py— validates the new rate limit configuration structuretest_repository_rate_limits.py— ensures repository-level limits are correctly appliedtest_subscription_rate_limiting.py— significant rework (~60 lines changed) to align with the refactored middleware behaviortest_subscription_rate_limits.py— updated assertions to match the simplified configurationInfrastructure Considerations
🤖 Generated with Claude Code
Branch Info:
chore/search-rate-limitsmainCo-Authored-By: Claude noreply@anthropic.com