Add language aggregations for Zoekt code search (backend)
What does this MR do and why?
Issue: #392882
Split from !243585 — this is MR 1 of 2 (backend). See the frontend follow-up in the description of this MR once it's opened.
Adds the backend for Zoekt language aggregations in code search, gated behind the zoekt_language_aggregations feature flag (default off). Nothing in the UI changes until the frontend MR lands.
Why split
Per reviewer guidance, shipping new GraphQL fields together with the frontend that requests them creates a Self-Managed upgrade window where the frontend asks for fields the backend doesn't yet know about, producing GraphQL errors that can make the app unresponsive. Splitting backend-first eliminates that window.
Backend changes
- New
languagefilter argument on the GraphQLblobSearchresolver so callers can narrow Zoekt results to specific detected languages. - Threads the language filter through
Search::Zoekt::CodeQueryBuilder,MultiMatch,SearchRequest, andSearchResults. - Adds
Search::Zoekt::AggregationCache: a standalone Redis cache for language-bucket tallies, keyed independently of pagination and of the language filter itself so bucket counts stay stable across faceted ticks. Includessearch_modein the fingerprint so regex and exact tallies don't collide. - Exposes
zoekt_language_aggregations_enabled?onSearchServicePresenter, wired throughapp/views/search/show.html.hamlso the frontend can read the flag fromgononce the frontend MR lands.
Frontend follow-up
The frontend MR (to be opened after this one) consumes the new language argument behind @gl_introduced(version: "18.3.0") on the GraphQL query field, so older Self-Managed instances that don't yet have this backend deployed skip the field gracefully instead of erroring.
Note on the diff
doc/api/graphql/reference/_index.md and public/-/graphql/introspection_result.json contain a couple of lines unrelated to this feature (SecretsManagementAction.READ_VALUE) — those are the result of regenerating the derived GraphQL docs against current master, which merged a security fix that added that enum value. Regeneration is required by the pre-push check (graphql_introspection_check, graphql_docs); leaving them stale isn't an option.
MR acceptance checklist
- Changes are behind a feature flag:
zoekt_language_aggregations - Test plan covered by new specs under
ee/spec/lib/search/zoekt/*_spec.rbandee/spec/requests/api/graphql/search/blob_search_spec.rb