Add GQL query transport to Orbit

What does this MR do and why?

Adds a default-off orbit_gql_queries flag that selects JSON or GQL across regular queries, named queries, discovery, and the dashboard editor. Rails reads the flag for the current user and sends the matching language on every Orbit request. It does not inspect the query itself: the Orbit compiler rejects text in the wrong language. REST, MCP, and header inputs cannot override the choice, because Orbit reads the language only from the request field Rails sets.

The flag uses a user actor only, so it can be enabled for team members with --feature-group=gitlab_team_members.

References

Screenshots or screen recordings

The editor loads the template for the current mode, and "My neighbors in the graph" runs in both. Each mode returns the same 99 nodes with the same entity counts.

JSON mode (flag off) GQL mode (flag on)
JSON mode GQL mode

Both screenshots come from local GDK, running this branch against the Orbit server from the Orbit implementation branch.

Named queries

The editor offers 5 of the 12 named queries as templates. Each template returns the same results in both modes.

Named query templates in JSON and GQL mode
Template JSON mode (flag off) GQL mode (flag on)
my_neighbors (99 results) my_neighbors JSON my_neighbors GQL
mrs_fixing_vulnerabilities (15 results) mrs_fixing_vulnerabilities JSON mrs_fixing_vulnerabilities GQL
my_mrs_with_pipelines (5 results) my_mrs_with_pipelines JSON my_mrs_with_pipelines GQL
recent_merges (13 results) recent_merges JSON recent_merges GQL
top_mr_authors (22 results) top_mr_authors JSON top_mr_authors GQL

The other 7 named queries take parameters, so the editor doesn't list them. Through POST /api/v4/orbit/query/:name, every one returned HTTP 200 and the same nodes, edges, and rows in both modes.

Named query Rows JSON = GQL
definition_callees 49 Yes
definition_references 19 Yes
expand_neighbors 49 Yes
file_definition_callers 81 Yes
file_definitions 25 Yes
list_nodes 50 Yes
search_nodes 3 Yes

How to set up and validate locally

  1. Run the Workhorse routing tests.

    go -C workhorse test ./internal/orbit
  2. Run the Rails specs.

    bundle exec rspec \
      ee/spec/lib/analytics/knowledge_graph_spec.rb \
      ee/spec/lib/analytics/knowledge_graph/grpc_client_spec.rb \
      ee/spec/helpers/dashboard/orbit_helper_spec.rb \
      ee/spec/lib/ee/gitlab/workhorse_spec.rb \
      ee/spec/lib/api/orbit/mcp_handlers/call_tool_spec.rb \
      ee/spec/requests/api/orbit/data_spec.rb \
      ee/spec/requests/api/orbit/mcp_spec.rb
  3. With the flag off, confirm all 12 named queries return HTTP 200 in JSON mode and discovery does not mention GQL.

  4. Enable the flag for a test user. Confirm the same queries return equivalent results in GQL mode.

  5. In each mode, send a query in the other language. Confirm the Orbit compiler returns HTTP 400.

Local GDK validation ran all 12 named queries in both modes. Every request returned HTTP 200, and normalized results matched. The dashboard also rendered and executed top_mr_authors in both modes. Focused Orbit, Workhorse, Ruby, Jest, and lint checks passed.

After the review changes, a second local run passed with the flag on and with it off. All 12 named queries returned rows and matched across modes. It covered REST /orbit/query (raw and llm), named queries, templates, agent commands, query_graph, and MCP invoke_command. A query in the wrong language returned the compiler's HTTP 400. get_query_dsl returned 404 in GQL mode, as designed.

After bumping to the published 0.130.0 clients, the Workhorse Orbit tests passed, the Rails specs above passed (492 examples, 0 failures), and graph_explorer_spec.js passed (48 tests).

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist.

  • Add a default-off feature flag and rollout issue.
  • Add API documentation and tests for query selection and forwarding.
  • Merge Orbit MR !2460, publish the Go and Ruby protobuf clients, and bump both pins.
  • Run the full Rails specs after the dependency bump.

No changelog entry is needed while this feature remains behind a default-off flag.

Agent context

The protobuf contract keeps QueryType values JSON=0 and NAMED=1. A separate QueryLanguage enum uses JSON=0 and GQL=1 on six requests. Query type selects raw or named input; language selects the compiler, named-query spelling, and discovery guidance.

Workhorse pins orbitpb v0.130.0 and Rails pins gitlab-orbit-proto 0.130.0, both of which include the enum and fields. Orbit must run 0.130.0 or later before the flag is enabled. Disable the flag before rolling back any component.

Edited by Aaron Algutifan

Merge request reports

Loading
Loading