Skip to content

fix(gov): enforce daily index call limits - #5144

Merged
KrisOei merged 5 commits into
mainfrom
kris/gov-daily-search-limit
Oct 15, 2026
Merged

KrisOei merged 5 commits into
mainfrom
kris/gov-daily-search-limit

Conversation

@KrisOei

@KrisOei KrisOei commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator

Limit government-index calls per team per UTC day across /v2/search/gov, gov-category search, and the government Alexandria provider. Non-gov requests retain their existing behavior.

  • Configure the daily budget with GOV_INDEX_CALLS_PER_DAY (default: 500).
  • Count each government-provider call in a batch and reject over-budget requests with 429 and Retry-After.
  • Bound Redis waits, fail open on Redis errors, and refund unexecuted reservations at most once, including late admissions.
  • Register the API-level quota error without changing worker error behavior.

Validation: API build, formatting, and targeted local unit/regression checks. Additional validation tests remain local; the PR contains production changes only.

The gov index is free and reachable as an Alexandria provider that the
Exchange calls in-cluster, past the per-minute limiters, with up to 10 calls
per request. One team ran about 223k gov searches in a day and saturated the
search-index reranker.

Every path into a free index now spends from one per-team budget per UTC day,
one unit per call, so a 10-call batch spends 10: the Alexandria provider,
/v2/search/gov and the gov category on /v2/search. A request that does not fit
is refused whole with 429 and Retry-After, before any quote or execution, and
spends nothing. Redis failures fail open.

Gov is limited at GOV_INDEX_CALLS_PER_DAY (default 500). The research index is
wired the same way but stays unlimited until RESEARCH_INDEX_CALLS_PER_DAY is
set.

Also drops the unused isPale export flagged by knip.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 7 files

This PR changes payment, billing, or quota logic. Ultrareviews find 2.4x more serious bugs than standard reviews. Comment @cubic-dev-ai ultrareview to run one.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread apps/api/src/config.ts Resolved
Comment thread apps/api/src/controllers/v2/search.ts Resolved
…alues

- Alexandria: index calls reserved before the quote and credit hold are given
  back on every refusal before execution (and on an exception), so transient
  quote or billing failures no longer burn a team's daily budget. Refusals
  after the Exchange executed still count.
- Alexandria: send the Retry-After header when a refusal carries
  retryAfterSeconds, as the other gov paths do.
- /v2/search: reserve the gov call immediately before executeSearch, after
  every rejecting validation, so a 403 spends nothing.
- Config: blank GOV_INDEX_CALLS_PER_DAY falls back to 500 and a blank
  RESEARCH_INDEX_CALLS_PER_DAY stays unset, instead of coercing to 0.
- Bound the Redis wait at 500 ms: an unreachable Redis queues commands rather
  than failing, which broke the fail-open promise.
- Tests: release and rollback, Retry-After on the Alexandria route, the
  /v2/search/gov 429, gov-only counting in retrieve, and gov-search tests no
  longer depend on a live Redis.
@KrisOei
KrisOei requested a review from mogery as a code owner October 15, 2026 05:23
- /v2/search/gov reserves after the request is logged, like /v2/search, so a
  failed log spends nothing, and gives the call back when the index is not
  configured.
- The gov daily-limit 429 on /v2/search and /v2/search/gov carries
  code INDEX_DAILY_LIMIT, so clients can tell it from the per-minute limiter
  and stop retrying until the reset (Alexandria already returns
  index_daily_limit).
- Correct the config comment: gov defaults to 500; only research is
  unlimited while unset.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 9 files (changes from recent commits).

Tip: Get a Slack DM when cubic finishes reviewing your PRs. Connect Slack

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread apps/api/src/lib/index-daily-limit.ts Resolved
- Alexandria: set Retry-After only for the index_daily_limit refusal. The
  Exchange already returns retryAfterSeconds for other providers' refusals,
  which keep their existing responses.
- After a Redis timeout the reservation command can still land once Redis
  reconnects. Its release now waits for that command in the background and
  gives back what it took, so a request refused before it ran spends nothing.
  A synchronous eval throw is also caught.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 11 files (changes from recent commits).

Requires human review: Auto-approval blocked because this review re-detected 1 unresolved P0–P2 issue already reported by Cubic.
Tip: Review your code locally with the cubic CLI to iterate faster.

View guided diff | Turn on auto-fix | Re-trigger cubic

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 9 files (changes from recent commits).

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Requires human review: Auto-approval blocked by 1 unresolved P0–P2 issue from previous reviews.

View guided diff | Turn on auto-fix | Re-trigger cubic

Restrict daily quotas to government index requests and leave other indexes unchanged. Make reservation refunds idempotent and register the API-level quota error.
@capy-ai capy-ai Bot changed the title Cap free index calls per team per day (gov at 500) fix(gov): enforce daily index call limits Oct 15, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 12 files (changes from recent commits).

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

View guided diff | Turn on auto-fix | Re-trigger cubic

@KrisOei
KrisOei merged commit b24ee93 into main Oct 15, 2026
10 checks passed
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.

1 participant