Skip to content

fix(ADS-678): name the enterprise quota in the 429 message - #453

Open
SH4DY wants to merge 1 commit into
mainfrom
fix/ADS-678-enterprise-quota-message
Open

fix(ADS-678): name the enterprise quota in the 429 message#453
SH4DY wants to merge 1 commit into
mainfrom
fix/ADS-678-enterprise-quota-message

Conversation

@SH4DY

@SH4DY SH4DY commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

Why

The 429 handler in verify_api.py hardcoded a single message for every rate-limit response:

Daily usage limit reached for the public version of Agent-Scan. Unlock higher limits and enterprise features by contacting us at ...

So an enterprise push-key caller who exhausts the enterprise budget is told they are on the public tier and should contact sales for enterprise features. That happened on PC01 this morning: cost.24h for budget:enterprise hit $530.86 against a $500/day cap, and the message pointed the investigation at auth and routing instead of at spend.

How

A push key routes the scan to /hidden/mcp-scan/analysis-machine, which the backend hardcodes to budget=ENTERPRISE; everything else goes to the CLI route and get_budget_for_user, which yields the public tier. The caller therefore already knows which budget applies, with no need to parse the response body:

elif e.status == 429:
    error_text = (
        "Daily usage limit reached for the enterprise version of Agent-Scan. "
        "Please contact support to increase your quota."
        if push_key
        else "Daily usage limit reached for the public version of Agent-Scan. ..."
    )

The remedy sentence mirrors the backend's own 429 detail for that bucket ("Please contact support to increase your quota"), so the CLI and API now say the same thing.

Tests

Adds test_429_with_push_key_names_the_enterprise_quota, asserting the enterprise wording and that "public version" is absent. The existing parametrized 429 case runs without a push key, so it still covers the public path unchanged.

ruff, ruff-format and mypy pass on both files. tests/unit/test_verify_api.py goes from 85 to 86 passing, with the same 8 pre-existing failures before and after.

Follow-up worth considering

Keying off push_key is accurate for the two real cases but does not cover internal_tier, which the backend can also return for internal principals. Reading the backend's 429 detail would be exact, but raise_for_status() discards the body, so it needs a small refactor of the error path.

Made with Cursor

The 429 handler hardcoded one message for every rate-limit response, telling
enterprise push-key callers they had hit the limit on "the public version of
Agent-Scan" and should contact sales to unlock enterprise features. When PC01
exhausted its enterprise budget this morning that message sent the on-call
looking at auth and routing rather than at spend.

A push key puts the scan on the enterprise budget and everything else on the
public one, so the caller already knows which applies without reading the
response body. The backend draws the same distinction in its own 429 detail.

Co-authored-by: Cursor <cursoragent@cursor.com>
@SH4DY
SH4DY requested a review from a team as a code owner August 27, 2026 07:48
@qodo-merge-etso

Copy link
Copy Markdown

PR Summary by Qodo

Show enterprise quota guidance for push-key 429 responses

🐞 Bug fix 🧪 Tests 🕐 10-20 Minutes

Grey Divider

AI Description

• Distinguishes enterprise and public quota exhaustion messages for HTTP 429 responses.
• Directs push-key users to support instead of the enterprise sales flow.
• Adds regression coverage preserving public messaging and validating enterprise wording.
Diagram

graph TD
  A["Analysis request"] --> B["HTTP 429"] --> C{"Push key?"}
  C -->|Yes| D["Enterprise quota"] --> F["Scan error"]
  C -->|No| E["Public quota"] --> F
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Use backend 429 detail
  • ➕ Exactly represents enterprise, public, and future internal budget tiers.
  • ➕ Keeps CLI guidance synchronized with backend quota remedies.
  • ➖ Requires refactoring the current raise-for-status error path to retain the response body.
  • ➖ Introduces parsing and fallback behavior beyond this targeted incident fix.

Recommendation: Keep the push-key conditional for this focused fix because it accurately covers the two production routes without changing HTTP error handling. Follow up by consuming a structured backend quota detail if internal-tier messaging must also be exact.

Files changed (2) +59 / -1

Bug fix (1) +12 / -1
verify_api.pySelect 429 quota guidance by push-key context +12/-1

Select 429 quota guidance by push-key context

• The HTTP 429 handler now identifies push-key requests as enterprise-budget calls and directs them to support for quota increases. Non-push-key requests retain the existing public-tier limit and enterprise upsell message.

src/agent_scan/verify_api.py

Tests (1) +47 / -0
test_verify_api.pyCover enterprise push-key quota messaging +47/-0

Cover enterprise push-key quota messaging

• Adds an async regression test that simulates a 429 response for a push-key analysis request. It verifies every returned scan error names the enterprise quota and excludes public-tier wording, while the existing parametrized case continues covering public requests.

tests/unit/test_verify_api.py

@qodo-merge-etso

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (1) 📎 Requirement gaps (0) 📜 Skill insights (0)

Grey Divider


Informational

1. 429 test duplicates mock setup 📘 Rule violation ☼ Reliability
Description
The new regression test copy-pastes the ClientSession, response, and ClientResponseError
construction from the adjacent parametrized test instead of reusing a fixture/helper. This creates
two setup paths that must remain synchronized when HTTP mocking changes.
Code

tests/unit/test_verify_api.py[R875-878]

+        with patch("agent_scan.verify_api.aiohttp.ClientSession") as mock_session_class:
+            mock_session = MagicMock()
+
+            mock_request_info = MagicMock()
Relevance

● Weak

Recent precedents reject duplicative test setup/helper extraction requests in this file and nearby
unit tests.

PR-#397
PR-#354

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 5 requires near-identical logic to be moved to or reused from a shared utility. The
newly added setup at lines 875-900 repeats the existing setup at lines 825-850, including session
creation, request info, response error, async context-manager mocks, and session wiring.

Rule 5: Avoid duplication (DRY)—reuse utilities instead of copy-pasting
tests/unit/test_verify_api.py[825-850]
tests/unit/test_verify_api.py[875-900]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new enterprise-quota regression test duplicates the HTTP error/session mock setup already used by the adjacent parametrized error-response test.

## Issue Context
Keep the enterprise-specific assertions and push-key invocation, but centralize construction of the mocked `ClientSession`, response context manager, and `ClientResponseError` so both tests use one setup path.

## Fix Focus Areas
- tests/unit/test_verify_api.py[825-850]
- tests/unit/test_verify_api.py[875-900]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 8 rules

Grey Divider

Tip of the day
💡 Did you know, you can ask Qodo to dismiss a finding you disagree with, with your reason on record

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants