Repository navigation
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Apply the shared rate limiter to
/autocompleter, the remaining endpoint called out in A04 ofdocs/AUDIT-2026-11-02.md. The/researchpart of A04 was fixed in #54, but/autocompleterstill never called the limiter while making outbound requests to its configured backends.Root cause
autocompleterinsrc/web/handlers.rshad noClientAddrextractor parameter and never calledstate.limiter.check(...), unlike/searchand/research. With the limiter enabled,/searchreturns 429 once the budget is spent while/autocompleterkept answering — and each answer can fan out to external autocomplete backends, iterating over the comma-separated backend list from the request.Changes
src/web/handlers.rs:autocompleternow takes the samepeer: ClientAddrextractor assearch_get/researchand runs the existinglimiter_response(&state, state.limiter.check(peer.0, &headers, "json"))check immediately after the empty-query early return — before preferences, query parsing and any backend fetch. This is a straight transplant of the pattern already used by/research(which also passes"json");src/web/limiter.rsis unchanged.tests/integration.rs: new testautocompleter_is_rate_limited, modelled on the existingresearch_and_search_share_limits_before_outbound_requests. Withlimiter_max = 1andbackend=none(so the allowed request makes no outbound call), the first request returns 200 with[]and the second returns 429 with aRetry-Afterheader. The test fails on unmodified main (the second request returns 200).Scope is deliberately limited to the limiter. The audit also mentions bounding the number of backend candidates tried and an overall deadline for the autocompleter; both need values chosen, so they are left out here rather than smuggled into a pattern transplant. Happy to add them in a follow-up if wanted.
No dependencies, configuration, or response fields change. With the limiter disabled (the default), behaviour is unchanged.
Verification
Linux x86_64, Rust 1.99.1 (proxy environment variables excluded from the test process for the loopback fixtures, as in #52):
cargo test --test integration autocompleter_is_rate_limited— 1 passed. With the handler change reverted, the same test fails (second request returns 200 instead of 429), confirming it covers the bug.cargo test --test integration: 26 passed, 2 failed. The failures areraw_content_honors_a_configured_limit_above_eight_thousand_charactersandraw_content_uses_only_the_explicit_language_and_separates_cached_variants, which fail identically on unmodifiedmainin this sandbox (Japanese content extraction returns null; same environment family as thetests/pdf_pages.rsfailure noted in fix: parse the LLM query array as JSON instead of splitting on commas #134/fix: validate timeout_limit at the HTTP entry point instead of panicking on inf #135) and are unrelated to this change.cargo test --lib web::: 36 passed.cargo fmt --all -- --check: passed.cargo clippy --all-targets -- -D warnings: passed.Limitations
Other platforms are left to CI. The test asserts the 429 response; that no backend fetch happens before the check follows from the check's placement (the autocomplete backend URLs are hardcoded to public hosts, so unlike the
/researchtest there is no local fake to count outbound calls against).Related
Addresses the remaining
/autocompleterpart of A04 in the existing audit.AI assistance: implementation and tests.