feat(query): add a GQL response format for query results

What does this MR do and why?

This adds an optional gql response format that prints query results as a cypher-shell style table. Columns are the query's node aliases, and each cell holds the full node. Defaults stay unchanged, so the format can be compared with GOON before replacing it.

Relates to #1263

Testing

Formatter, server, CLI, and migration-ledger tests pass, and workspace clippy passes. Real output from a local GDK through Rails and Workhorse:

+------------------------------------------------------------------------------------+
| u                                             | g                                  |
+------------------------------------------------------------------------------------+
| (:User {id: 1, username: "root"})             | (:Group {id: 22, name: "Toolbox"}) |
| (:User {id: 6, username: "georgine_keebler"}) | (:Group {id: 22, name: "Toolbox"}) |
+------------------------------------------------------------------------------------+

2 rows, more available

Performance Analysis

  • This merge request does not introduce any performance regression. If a performance regression is expected, explain why.

Rows repeat full node bodies, so output is larger than GOON's. Token cost and agent accuracy still need an evals-harness comparison.

Agent context: format, validation, and follow-ups

The format specification is in ADR 019.

Format

  • Traversal columns are node aliases in pattern order; each row is one authorized, hydrated result row.
  • Aggregations use their group and metric output names. Node groups print as node literals.
  • Neighbors and path finding print a single path column, such as (:Group {id: 22})<-[:MEMBER_OF]-(:User {id: 1}).
  • Values use cypher-shell literals: quoted strings, TRUE, FALSE, and NULL. Long text keeps the GOON truncation limits.
  • The footer reports the row count, plus more available and the next cursor when paginated. Every traversal and aggregation row prints; duplicate paths and neighbors collapse, as in the raw format.
  • Truncated text adds a <key>_len property. Padding stops at 120 characters, so one long value does not widen every row.
  • The compiler does not keep RETURN expressions, so a returned property prints inside its node. The compiler is unchanged.

Other changes

  • Only the query command advertises gql. Graph-status accepts only raw and llm.
  • Unknown response-format integers fail before query execution. Schema queries under gql return TOON text.
  • Schema-version lookup reads only the schema pin, so historical versions.yaml files still parse after a new pin is added.
  • GOON 4.0.4 keeps edges that differ only in depth; it was dropping them.

[skip pinned-version-check]: shared formatter files match the raw pin's paths, but raw output is unchanged.

Validation

Companion Rails/Workhorse MR: gitlab-org/gitlab!258504. Real GDK requests through Rails and Workhorse returned tables for traversal, aggregation, neighbors, shortest path, named queries, and MCP. Earlier runs also confirmed invalid formats, anonymous access, and Rails redaction callbacks. The ClickHouse integration suite and agent evals were not run.

Required follow-ups

  1. Deploy the GKG release before enabling gql in GitLab; older servers return raw JSON for the new enum value.
  2. Land the companion Rails/Workhorse MR with a released protobuf client.
  3. Update glab-side format validation once GitLab accepts gql.
  4. Add the selected response format to query analytics through an Iglu schema change.
  5. Compare gql with llm in the evals harness before changing the default.
Edited by Aaron Algutifan

Merge request reports

Loading
Loading